Affichage_Atrylec_com

Vous n'êtes pas seuls dans l'Univers !

Transistor_100

Les expanseurs de port I2C

Les expanseurs de port I2C.
Pour de nombreuses réalisations électroniques à base de microcontrôleur ou de FPGA, il est nécéssaire d'avoir un nombre conséquent d'entrées-sorties.

Je veux remonter ! | Liste

1) Intérêt et présentation

Il s'avère parfois également utile de pouvoir lire des entrées ou de commander des sorties depuis la carte de commande d'un appareil, alors que ces entrées-sorties ne se situent pas à proximité immédiate de cette carte de commande.

Plutôt que de recourir à des microcontrôleurs ou à des FPGA possédant beaucoup de broches d'entrées-sorties, ou à passer de nombreux câbles entre deux endroits éloignés d'un dispositif, il peut être intéressant de recourir à des expanseurs de ports, en particulier à des expanseurs de ports commandés par un bus I2C ( « Remote I/O expander for I2C-bus » ).

documentaires-des-proprietes-icone-5224-32

Exemple : Supposons que vous ayez une machine composée d'un panneau avant et d'une carte de commande, équipée d'un microcontrôleur.
Le panneau avant contient huit voyants lumineux.
Sans expanseur de port I2C, il faudrait réserver huit sorties du microcontrôleur pour les huit voyants lumineux.
Puis, il conviendrait de faire passer au moins neuf fils entre la carte de commande et le panneau avant, si l'on considère que l'on utilise un fil par voyant, et un fil pour le point commun.
Avec un expanseur de port I2C, il suffit de réserver deux broches du microcontrôleur pour gérer le bus I2C, et le câblage entre la carte de commande et la face avant ne nécessite plus que quatre fils : deux pour alimenter l'expanseur de port I2C, et deux pour faire transiter les données.

Je veux remonter ! | Liste

2) Fonctionnement d'un expanseur de port I2C

Un expanseur de port I2C dispose de généralement 8 ou 16 entrés-sorties dont l'état peut être consulté ou modifié par un microcontrôleur ou un FPGA connecté grâce à un bus I2C.

Ce bus est composé de deux fil, en plus du fil dont le potentiel sert de référence : un fil qui transmet les données, qui est souvent nommé « SDA », pour « Serial DAta », et un fil qui transmet le signal d'horloge permettant de synchroniser la réception des données, qui est généralement nommé « SCL », pour « Serial CLock ».

Vis-à-vis de la liaison I2C, un expanseur de port I2C est un composant de type « Esclave », ( « Slave » ), car il reçoit et effectue les ordres que lui envoie un microcontrôleur ou un FPGA, qui joue, quant à lui, le rôle de « Maître » ( « Master » ).

Cela veut donc dire qu'un expanseur de port I2C doit avoir une adresse sur le bus I2C où il est mis en œuvre.
Cela permet de mettre plusieurs expanseurs de port I2C sur le même bus, sans que tous effectuent le même ordre.

Les adresses de ces composants sont codées sur huit bits.
Le bit de poids faible sert à définir l'opération que le maître souhaite effectuer.
Si le maître le met à « un », il s'agira d'une opération de lecture de l'état logique d'une broche, ou de la lecture du contenu d'un registre de configuration, pour certains expanseurs de ports I2C.
Si le maître le met à « zéro », il s'agira d'une opération d'écriture, qui visera à changer l'état logique d'une broche, ou du contenu d'un registre de configuration.

La plupart des expanseurs de ports I2C sont pourvus d'une broche qui change d'état logique lorsqu'au moins une entrée, parmi celles que comporte le circuit, a changé d'état depuis la dernière fois que celui-ci a été consulté par le maître.
Cela permet, si cette broche est reliée à une entrée du maître, d'indiquer à ce dernier que quelque chose s'est passé du côté d'un expanseur de port I2C, par exemple que quelqu'un a appuyé sur un bouton-poussoir.
Cette broche porte souvent le nom « INT », car, si elle est reliée à une entrée d'un microcontrôleur maître correctement configuré, son changement d'état provoquera une interruption dans le programme de ce microcontrôleur.
Ainsi, il saura qu'il devra interroger l'expanseur de port I2C qui aura envoyé un signal sur sa broche « INT ».
Tant qu'aucune entrée de l'expanseur de port I2C n'aura changé d'état, le programme principal du microcontrôleur maître pourra continuer à s'exécuter, sans qu'il n'ait besoin d'interroger en permanence l'expanseur pour voir s'il s'est passé quelque chose au niveau de ses entrées.

Je veux remonter ! | Liste

3) Quelques essais d'expanseurs de port I2C

Il existe de nombreuses références de circuits intégrés qui assurent la fonction d'expanseur de port I2C.
Le tableau comparatif suivant permet de résumer les caractéristiques de quelques-uns de ces circuits intégrés.

PCF8574 PCF8574A PCF8575 MCP23016 MCP23017
Nombre de broches 16 16 24 28 28
Nombre d'entrées-sorties disponibles 8 8 16 16 16
Fréquence maximale de fonctionnement 100 kHz 100 kHz 400 kHz 400 kHz 1,7 MHz
Composants externes nécessaires Aucun Aucun Aucun
  • 1 résistance

  • 1 condensateur
Aucun
Nombre de sorties d'interruption 1 1 1 1 2
Gamme d'adresses possibles sur le bus I2C 0x40 - 0x4F 0x70 - 0x7F 0x40 - 0x4F 0x40 - 0x4F 0x40 - 0x4F
Nombre d'adresses possibles sur le bus I2C 8 8 8 8 8
avertissement-icone-9768-32

Attention ! A la lecture de ce tableau, on constate qu'il n'est pas possible de faire cohabiter sur le même bus I2C, par exemple,
un circuit intégré « PCF8574 » et un circuit intégré « MCP23016 »,
si ces deux circuits n'ont pas une adresse différente.

Les exemples de codes sources présentés ci-après mettent en œuvre un microcontrôleur PIC18F4550 et un microcontrôleur STM32F100RB.

Code source : Exemple 1 - Configurer la connexion du bus I2C d'un PIC18F4550 en tant que « Maître »


TRISBbits.RB0 = 1;   /* Configuration de la broche « RB0/AN12/INT0/FLT0/SDI/SDA » du PIC18F4550 en entrée numérique */
TRISBbits.RB1 = 1;   /* Configuration de la broche « RB1/AN10/INT1/SCK/SCL » du PIC18F4550 en entrée numérique */

OpenI2C(MASTER, SLEW_OFF);   /* Ouverture de la connexion I2C, en tant que maître,
					sans le contrôle du temps de montée ( « Slew Rate » ),
					adapté au mode « Standard Speed » (100 kHz et 1 MHz) */

SSPADD = 0x28;  /* Réglage de la fréquence du bus I2C à 100 kHz, si l'horloge du PIC18F4550 est réglée à 4 MHz */

3-1) PCF8574 et PCF8574A

PCF8574.

Exemple avec un microcontrôleur « PIC18F4550 ».

Code source : Exemple 2 - Envoyer une donnée de huit bits à un « PCF8574 », ou à un « PCF8574A »


int Ecrire(unsigned char adresse, unsigned char donnee) 
{
	int information = -1;

	IdleI2C();    /* Attente de la disponibilité du bus I2C */
	StartI2C();    /* Envoi de message de début de la communication I2C */
	IdleI2C();    /* Attente de la disponibilité du bus I2C */

	putcI2C(adresse); /* Envoi de l'adresse de l'esclave */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if(SSPCON2bits.ACKSTAT) /* Si AckStat == 1, on n'a pas reçu d'acquittement de la part de l'esclave */
	{
		StopI2C();  /* Envoi de message de fin de la communication I2C */

		return information;   /* On renvoie -1, ce qui indique qu'il y a eu un problème */
	}

	putcI2C(donnee);   /* On envoie la valeur */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if(!(SSPCON2bits.ACKSTAT)) /* Si on reçoit un acquitement de la part de l'esclave,
	on retournera 1 à la fin de la fonction */
	{
		information = 1;
	}

	StopI2C();    /* Envoi de message de fin de la communication I2C */

	return information;
}


Code source : Exemple 3 - Lire une donnée de huit bits à un « PCF8574 », ou à un « PCF8574A »


int Lire(unsigned char adresse)
{
	int valeur = -1;

	IdleI2C();    /* Attente de la disponibilité du bus I2C */
	StartI2C();    /* Envoi de message de début de la communication I2C */
	IdleI2C();    /* Attente de la disponibilité du bus I2C */

	putcI2C(adresse); /* Envoi de l'adresse de l'esclave */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if (SSPCON2bits.ACKSTAT) /* Si AckStat == 1, on n'a pas reçu d'acquittement de la part de l'esclave */
	{
		StopI2C();  /* Envoi de message de fin de la communication I2C */

		return valeur;   /* On renvoie -1, ce qui indique qu'il y a eu un problème */
	}

	valeur = ReadI2C(); /* Lecture de la valeur qui est reçue sur le bus I2C */

	NotAckI2C();   /* On n'envoie pas d'acquittement car on lit qu'un seul caractère */

	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	StopI2C();   /* Envoi de message de fin de la communication I2C */

	return valeur;   /* On renvoie la valeur lue */
}


Exemple mettant en œuvre deux cartes à expanseurs PCF8574 et une carte de développement de type « STM32VLDISCOVERY », équipé d'un microcontrôleur « STM32F100RB ».
Les connexions entre les expanseurs et la carte de développement sont indiquées dans le tableau ci-après.
Les broches « PB6 » et « PB7 » sont reliées au + 5 volts par des résistances de tirage de 1 kilo Ohm.

Carte de développement « STM32VLDISCOVERY » +5V 0V PB6 PB7
Circuits intégrés PCF8574 +5V 0V SCL SDA
Expanseur_I2C_modele_PCF8574_et_STM32VLDISCOVERY_1 Expanseur_I2C_modele_PCF8574_et_STM32VLDISCOVERY_2 Expanseur_I2C_modele_PCF8574_et_STM32VLDISCOVERY_3
Essais avec deux cartes à expanseurs « PCF8574 » et une carte de développement de type « STM32VLDISCOVERY »
fleche-bas-telecharger-icone-9594-32

Communiquer avec un PCF8574 : Fichier C
Cible : STM32F100RB
Compilateur : Keil µVision4
Télécharger le fichierEffectuez un clic droit, puis sélectionnez l'option « Enregistrer la cible du lien sous... », pour télécharger le fichier (2.37 Ko)

3-2) PCF8575

PCF8575.

3-3) MCP23016

MCP23016.

Exemple avec un microcontrôleur « PIC18F4550 ».

Code source : Exemple 4 - Ecrire dans un registre d'un « MCP23016 », ou d'un « MCP23017 »


int Ecrire16Nouvelle(unsigned char adresse, unsigned char commande, unsigned char donnee1, unsigned char donnee2) 
{
	int information = -1;

	IdleI2C();    /* Attente de la disponibilité du bus I2C */
	StartI2C();    /* Envoi du message de début de la communication I2C */
	IdleI2C();    /* Attente de la disponibilité du bus I2C */

	putcI2C(adresse); /* Envoi de l'adresse de l'esclave */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if(SSPCON2bits.ACKSTAT) /* Si AckStat == 1, on n'a pas reçu d'acquittement de la part de l'esclave */
	{
		StopI2C();  /* Envoi du message de fin de la communication I2C */

		return information;   /* On renvoie -1, ce qui indique qu'il y a eu un problème */
	}

	putcI2C(commande);   /* On envoie la valeur de « commande » */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if(SSPCON2bits.ACKSTAT) /* Si AckStat == 1, on n'a pas reçu d'acquittement de la part de l'esclave */
	{
		StopI2C();  /* Envoi du message de fin de la communication I2C */

		return information;   /* On renvoie -1, ce qui indique qu'il y a eu un problème */
	}

	putcI2C(donnee1);   /* On envoie la valeur de « donnee1 » */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if(SSPCON2bits.ACKSTAT) /* Si AckStat == 1, on n'a pas reçu d'acquittement de la part de l'esclave */
	{
		StopI2C();  /* Envoi du message de fin de la communication I2C */

		return information;   /* On renvoie -1, ce qui indique qu'il y a eu un problème */
	}

	putcI2C(donnee2);   /* On envoie la valeur de « donnee2 » */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if(!(SSPCON2bits.ACKSTAT)) /* Si on reçoit un acquitement
	de la part de l'esclave,
	on retournera 1 à la fin de la fonction */
	{
		information = 1;
	}

	StopI2C();  /* Envoi du message de fin de la communication I2C */

	return information;
}


Code source : Exemple 5 - Lire un registre d'un « MCP23016 », ou d'un « MCP23017 »


int Lire16Nouvelle(unsigned char adresse, unsigned char commande, unsigned char adresse_de_lecture,
unsigned char * donnee1, unsigned char * donnee2)
{
	int information = -1;

	IdleI2C();    /* Attente de la disponibilité du bus I2C */
	StartI2C();    /* Envoi du message de début de la communication I2C */
	IdleI2C();    /* Attente de la disponibilité du bus I2C */

	putcI2C(adresse); /* Envoi de l'adresse de l'esclave */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if(SSPCON2bits.ACKSTAT) /* Si AckStat == 1, on n'a pas reçu d'acquittement de la part de l'esclave */
	{
		StopI2C();  /* Envoi du message de fin de la communication I2C */

		return information;   /* On renvoie -1, ce qui indique qu'il y a eu un problème */
	}

	putcI2C(commande);   /* On envoie la valeur de « commande » */
	IdleI2C();   /* Attente de la disponibilité du bus I2C */

	if(SSPCON2bits.ACKSTAT) /* Si AckStat == 1, on n'a pas reçu d'acquittement de la part de l'esclave */
	{
		StopI2C();  /* Envoi du message de fin de la communication I2C */

		return information;   /* On renvoie -1, ce qui indique qu'il y a eu un problème */
	}

	StopI2C();  /* Envoi du message de fin de la communication I2C : l'expanseur de port I2C « MCP23016 » 
											sait désormais que la prochaine opération de lecture
											concernera le registre dont la valeur vaut « commande » */

	IdleI2C();    /* Attente de la disponibilité du bus I2C */
	StartI2C();    /* Envoi du message de début de la communication I2C */
	IdleI2C();    /* Attente de la disponibilité du bus I2C */

	putcI2C(adresse_de_lecture); /* Envoi de l'adresse de lecture de l'esclave */
	IdleI2C();    /* Attente de la disponibilité du bus I2C */

	if(SSPCON2bits.ACKSTAT) /* Si AckStat == 1, on n'a pas reçu d'acquittement de la part de l'esclave */
	{
		StopI2C();  /* Envoi du message de fin de la communication I2C */

		return information;   /* On renvoie -1, ce qui indique qu'il y a eu un problème */
	}

	*donnee1 = ReadI2C(); /* Lecture de la valeur de « donnee1 », qui est reçue sur le bus I2C */
	AckI2C();   /* On renvoie un acquittement,
									conformément aux informations données par la datasheet
									de l'expanseur de port I2C « MCP23016 » */
	IdleI2C();    /* Attente de la disponibilité du bus I2C */

	*donnee2 = ReadI2C(); /* Lecture de la valeur de « donnee2 », qui est reçue sur le bus I2C */
	NotAckI2C();   /* On ne renvoie pas d'acquittement,
									conformément aux informations données par la datasheet
									de l'expanseur de port I2C « MCP23016 » */
	IdleI2C();    /* Attente de la disponibilité du bus I2C */

	StopI2C();  /* Envoi du message de fin de la communication I2C */

	information = 1;

	return information;   /* On renvoie 1, ce qui indique que tout s'est bien passé */
}


3-4) MCP23017

MCP2317.

Commentaires (0)

Ajouter un commentaire

Votre pseudo :

Votre commentaire :

Je veux remonter !