I2C SIMPLEX, Control ON/OF: 1 Host - 3 Clients. EN/ES

avatar

The I2C protocol is in the category of complex understanding taking into account that my articles are addressed to any reader, this poses a series of challenges for me to find a way to explain it in such a way that its understanding becomes easy for my beloved readers.

It is necessary to hold on to the knowledge acquired in previous articles in order to achieve this goal. In fact all the articles I have written have had an intentional sequence of topics in order to acquire the basic knowledge that will allow us to understand deeper topics, so it is important to try to master them (for those who are really interested in learning electronics).

Following this order of ideas I have tried to write this article in a way that we can use the I2C protocol in a practical application but easy to understand so we will make a connection between a master (host) and 3 slaves (clients) in a SIMPLEX mode (unidirectional), we only want to study the way in which communication is established, so we will not add complexity in the application so that the code does not become long and complex (at least not in this article), so that we will only turn on and off a led in each slave microcontroller (client) so that the weight of knowledge is focused on the operation of the I2C protocol.


El protocolo I2C está en la categoría de comprensión compleja tomando en cuenta que mis artículos son dirigidos a cualquier lector, esto plantea una serie de retos para mi respecto a encontrar una forma para explicarlo de tal manera que su comprensión se haga fácil para mis amados lectores.

Es necesario aferrarnos a los conocimientos adquiridos en artículos anteriores para poder lograr esta meta. De hecho todos los artículos que he escrito han llevado una secuencia intencional de temas con la finalidad de adquirir los conocimientos básicos que nos permitan comprender temas más profundos, por eso es importante intentar dominarlos (para los que realmente tengan interés de aprender electronica).

Siguiendo ese orden de ideas he intentado escribir este artículo de una forma que podamos usar el protocolo I2C en una aplicación práctica pero fácil de entender por lo cual vamos a realizar una conexión entre un maestro (host) y 3 esclavos (clientes) en un modo SIMPLEX (unidireccional), solo deseamos estudiar la forma en que se establece la comunicación, por lo cual no añadiremos complejidad en la aplicación para que el código no se haga largo y complejo (al menos no en este artículo), de tal forma que solo vamos a encender y apagar un led en cada microcontrolador esclavo (cliente) para que el peso del conocimiento esté enfocado en el funcionamiento del protocolo I2C.


Physical connection

After having seen some theory it is time to apply some of what we have learned, however we will also complement the theoretical information as we develop the topic.

We know that the I2C protocol uses two lines to establish communication, these are SCL which is used for synchronization and its state can only be modified by the Host (master) and SDA through which data can travel from the Host to any client and from any client to the Host, clients can not communicate with each other. It is also important to note that I2C accepts multiple Hosts.

In the case of the microcontroller we will use (PIC16F877A) the SCL connection is on Pin 18 and SDA on Pin 23.


Después de haber visto algo de teoría es tiempo de aplicar algo de lo aprendido, sin embargo tambien iremos complementando la información teórica a medida que desarrollaremos el tema.

Sabemos que el protocolo I2C utiliza dos líneas para establecer la comunicación, estas son SCL que se usa para la sincronización y su estado solo puede ser modificado por el Host (maestro) y SDA mediante la cual pueden viajar los datos desde el Host a cualquier cliente y desde cualquier cliente hacia el Host, los clientes no pueden comunicarse entre ellos. También es importante señalar que I2C acepta varios Hosts.

Para el caso del microcontrolador que usaremos (PIC16F877A) la conexión SCL se encuentra en el Pin 18 y SDA en el Pin 23.


No additional chip is required to adapt the connection between components communicating under the I2C protocol, just connect the pins of each component correctly to the SCL and SDA lines, however these lines must be referenced at a high level by means of PULL-UP resistors for the communication to be successful.


No se requiere ningún chip adicional para adaptar la conexión entre componentes que se comunican bajo el protocolo I2C, basta con conectar los pines de cada componente de forma correcta a las líneas SCL y SDA sin embargo estas líneas se deben referenciar a un nivel alto mediante resistencias de PULL-UP para que la comunicación se pueda realizar de forma exitosa.


To test the operation of the I2C bus we are going to try that a Host can send data to 3 clients, each client will have an associated LED and each LED will have associated 2 pushbuttons connected to the Host by means of which the leds of each client can be turned on or off from the Host using the I2C protocol.

The Host will be the microcontroller U1 and will have a total of 6 pushbuttons (two (on/off) to control the led of each client), these pushbuttons are connected in Port B and we address them with labels to place them near the led they control, that way it will be easier to observe the simulation.


Para comprobar el funcionamiento del bus I2C vamos a intentar que un Host pueda enviar datos a 3 clientes, cada cliente tendrá asociado un LED y cada LED tendrá asociado 2 pulsadores conectados al Host mediante los cuales se podrán encender o apagar los leds de cada cliente desde el Host usando el protocolo I2C.

El Host será el microcontrolador U1 y tendrá un total de 6 pulsadores (dos (encender/apagar) para controlar el led de cada cliente), estos pulsadores están conectados en el Port B y los direccionamos con etiquetas para colocarlos cerca del led que controlan, de esa forma será más fácil observar la simulación.



We have then that to control the LED of U2 we will use B0 to turn on and B1 to turn off, for the LED of U3 we will use B4 to turn on and B5 to turn off and for the LED of U4 we will use B2 to turn on and B3 to turn off.

Recall that each client microcontroller must have an assigned address because the way the I2C connection is made, all receive the data that are transmitted but only the master decides by the address which of them should read or write on the bus.


Tenemos entonces que para controlar el LED de U2 usaremos B0 para encender y B1 para apagar, para el LED de U3 usaremos B4 para encender y B5 para apagar y para el LED de U4 usaremos B2 para encender y B3 para apagar.

Recordemos que cada microcontrolador cliente debe tener una dirección asignada ya que de la forma en que se realiza la conexión I2C todos reciben los datos que son transmitidos pero solo el maestro decide mediante la dirección cuál de ellos debe leer o escribir en el bus.


Programming Host

The I2C protocol has details that are important to appreciate, for example the Host does not have an address, only the clients must have one, as the clients must be attentive to the moment in which the Host tries to communicate without this affecting the tasks they are executing is done through an interruption that is why the configurations in the Host present difference in that of the clients.

To configure the host additionally to the usual lines we add the I2C configuration line which has the following data:

#use I2C(MASTER, SDA=PIN_C4, SCL=PIN_C3, SLOW): The first parameter defines whether the microcontroller will be Host (Master) or client (Slave), the second enables the SDA pin and the third parameter SCL the last one chooses the baud rate being able to choose SLOW or FAST.


El protocolo I2C tiene detalles que son importantes apreciar, por ejemplo el Host no posee una dirección, solo los clientes deberán tener una, como los clientes deben estar atentos al momento en el que el Host intenté comunicar sin que esto afecte las tareas que estén ejecutando se hace mediante una interrupción por eso las configuraciones en el Host presentan diferencia en la de los clientes.

Para configurar el host adicionalmente a las líneas de costumbre añadimos la línea de configuración I2C que tiene los siguientes datos:

#use I2C(MASTER, SDA=PIN_C4, SCL=PIN_C3, SLOW): El primer parámetro define si el microcontrolador será Host (Master) o cliente (Slave), el segundo habilita el pin de SDA y el tercer parámetro SCL el último elige la velocidad de transmisión pudiendo elegir SLOW o FAST.


#include <16f877a.h>

#fuses HS,NOWDT,NOPROTECT,NOPUT,NOLVP,BROWNOUT

#use delay(clock=20M)

#use I2C(MASTER, SDA=PIN_C4, SCL=PIN_C3, SLOW)     

We enable Port B because that is where we are going to connect our pushbuttons, we define which PIN we are going to connect each pushbutton to.


Habilitamos el Puerto B porque ahí vamos a conectar nuestros pulsadores, definimos en que PIN vamos a conectar cada pulsador.


#use standard_io(B)

#define botton_0 PIN_B0                                  

#define botton_1 PIN_B1

#define botton_2 PIN_B2                                  

#define botton_3 PIN_B3

#define botton_4 PIN_B4                                  

#define botton_5 PIN_B5   

Recall that in the data frame to establish an I2C communication the Host must initiate communication (open the line), then send the address of the client with which you want to communicate and the client with that address confirms that it is ready to receive (ACK) then the Host sends the data and again the client confirms having received it correctly, finally the Host ends the communication (closes the line).

This must be done every time you want to establish a communication, it would be impractical to write the code for it every time, instead we are going to create a function with the code and what we do when we need to send a data will be to put it in the variables address and data (address and data) that are the values with which we define to whom the message goes and what is the message.


Recordemos que en la trama de datos para que se pueda establecer una comunicación I2C el Host debe iniciar la comunicación (abrir la línea), luego envía la dirección del cliente con el que se desea comunicar y el cliente con esa dirección confirma que está listo para recibir (ACK) entonces el Host envía los datos y de nuevo el cliente confirma haberlos recibido correctamente, finalmente el Host termina la comunicación (cierra la línea).

Esto se debe hacer cada vez que se desea establecer una comunicación, sería poco práctico escribir el código para ello cada vez, en lugar de ello vamos a crear una función con el código y lo que hacemos cuando necesitemos enviar un dato sera ponerlo en las variables dirección y dato (address y data) que son los valores con los que definimos a quien va el mensaje y cuál es el mensaje.


void sending_i2c(int address, int data);

Now let's write the function with the instructions in the correct order required by I2C, that is:

  • Start: i2c_start();
  • Send address: i2c_write(address);
  • Send data: i2c_write(data);
  • Stop transmission: i2c_stop();

It is important to note that we are not sending the acknowledgement (Ack) because this is done by the slave (client).


Ahora vamos a escribir la función con las instrucciones en el orden correcto que requiere I2C, esto es:

  • Iniciar: i2c_start();
  • Enviar dirección: i2c_write(address);
  • Enviar dato: i2c_write(data);
  • Detener transmisión: i2c_stop();

Es importante notar que no estamos enviando el reconocimiento (Ack) porque esto lo hace el esclavo (cliente).


void sending_i2c(int address, int data)                 

{

   i2c_start();           

   i2c_write(address);     

   i2c_write(data);        

   i2c_stop();             

   delay_ms(50);  

}

Now we must choose the addresses of our clients, for this U2 will be A8 which is controlled by pushbuttons B0 and B1, U3 will be A2 which is controlled by pushbuttons B4 and B5 and U4 will have the address A0 which is controlled by pushbuttons B2 and B3.

The states of each pushbutton will be queried and the data sent will be 10 to turn on the LED and 20 to turn it off.

Here we use the conditional If combined with the while loop to query the state of each pushbutton and send the appropriate data for the function to process and transmit.


Ahora debemos elegir las direcciones de nuestros clientes, para ello U2 será A8 que es controlado por los pulsadores B0 y B1, U3 será A2 que es controlado por los pulsadores B4 y B5 y U4 tendrá la dirección A0 que es controlado por los pulsadores B2 y B3.

Se consultarán los estados de cada pulsador y los datos enviados serán 10 para encender el LED y 20 para apagarlo.

Aquí nos valemos del condicional If combinado con el bucle while para consultar el estado de cada pulsador y enviar el dato adecuado para que la función procese y transmita.


void main()

{

   while(true)

   {

      if(input(botton_0) == 1)                            

      {

         while(input(botton_0) == 1)

         {

         delay_ms(5);

         sending_i2c(0xA8, 0x10);

         }

      }
      
      else if(input(botton_1) == 1)                           

      {

         while(input(botton_1) == 1)

         {

         delay_ms(5);

         sending_i2c(0xA8, 0x20);

         }

      }
      
      if(input(botton_2) == 1)                            

      {

         while(input(botton_2) == 1)

         {

         delay_ms(5);

         sending_i2c(0xA0, 0x10);

         }

      }
      
      else if(input(botton_3) == 1)                           

      {

         while(input(botton_3) == 1)

         {

         delay_ms(5);

         sending_i2c(0xA0, 0x20);

         }

      }
      
      else if(input(botton_4) == 1)                            

      {

         {

         while(input(botton_4) == 1)

         delay_ms(5);

         sending_i2c(0xA2, 0x10);

         }

      }
      
      else if(input(botton_5) == 1)                           

      {

         while(input(botton_5) == 1)

         {

         delay_ms(5);

         sending_i2c(0xA2, 0x20);

         }

      }

   }

}

Programming Clients

As the clients have the same application (turn on a LED) the same code will work for all of them (I decided this way to simplify, otherwise we would have to create three different programs apart from the master and there if we could saturate us of information, I did not see it convenient) so we will create the program once and to add it to each client the only thing that we will change will be the address that corresponds to that client.

In the I2C configuration line of the slave we must add the address parameter and if it can be controlled by software along with the other parameters that we use in the master. As we will use a LED we will enable a port to connect it, in this case it will be port B.


Como los clientes tienen la misma aplicación (encender un LED) el mismo código funcionará para todos ellos (lo decidi asi para simplificar, sino hubiera que crear tres programas distintos a parte del del maestro y ahi si podriamos saturarnos de información, no lo vi conveniente) así que crearemos el programa una vez y para añadirlo a cada cliente lo unico que vamos a cambiar sera la direccion que se corresponda a ese cliente.

En la línea de configuración I2C del esclavo debemos añadir el parámetro dirección y si se podrá controlar por software junto con los otros parámetros que usamos en el maestro. Como usaremos un LED habilitaremos un puerto para conectarlo, en este caso será el puerto B.


#include <16f877a.h>

#fuses HS,NOWDT,NOPROTECT,NOPUT,NOLVP,BROWNOUT

#use delay(clock=20M)

#use I2C(SLAVE, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=0xA8, SLOW, NOFORCE_SW)  

#use standard_io(B)

#define led_1 PIN_B0                                    

int data_received;      

To enable the I2C interrupt in the slave we use the #INT_SSP directive and then we write the function that will be executed in this interrupt, for this application we will only evaluate through a conditional if if i2c_poll() is true in which case we will read the data received with the i2c_read() instruction; this reading will give us the transmitted data which we must store in a variable to be able to use it.


Para habilitar la interrupción por I2C en el esclavo usamos la directiva #INT_SSP y posteriormente escribimos la función que se ejecutará en dicha interrupción, para esta aplicación solo evaluaremos mediante un condicional if si i2c_poll() es verdadero en cuyo caso leeremos los datos recibidos con la instrucción i2c_read(); esta lectura nos dará el dato transmitido el cual debemos almacenar en una variable para poder usarla.


#INT_SSP                                                

void interruption_i2c()

{

   if(i2c_poll())                                      

   {

     data_received = i2c_read();                         

   }

}

Now in the main program we will use the instruction
enable_interrupts(INT_SSP); to enable the I2C interrupt it is important to remember to always enable global interrupts to be able to work with any type of interrupt.


Ahora en el programa principal usaremos la instrucción
enable_interrupts(INT_SSP); para activar la interrupción por I2C es importante recordar que siempre hay que activar las interrupciones globales para poder trabajar con cualquier tipo de interrupción.


void main()

{

   enable_interrupts(INT_SSP);

   enable_interrupts(GLOBAL);

   output_low(led_1);

Finally, in an infinitely repeating while loop we use if conditionals to evaluate whether the received data is 10 to turn on the LED or 20 to turn it off.


Para finalizar, en un bucle while de repetición infinita usamos condicionales if para evaluar si el dato recibido es 10 para encender el LED o 20 para apagarlo.


   while(true)
 
  {

      if(data_received == 0x10)                          

      {

         output_high(led_1);                             

      }

      else if(data_received == 0x20)                       

      {

         output_low(led_1);                              

      }

   }

}

Simulation

For our simulation we will turn on each LED and evaluate the response, then we will turn on and off the same LED. An I2C DEBUGGER will be used to evaluate the data frame, an example of what we will see in it will be a frame where S indicates START then the next value is the address A means ACK the next value is the data, again A and then P which means pusa.


Para nuestra simulación iremos encendiendo cada LED y evaluando la respuesta, luego se harán encendido y apagado del mismo LED. Se usará un I2C DEBUGGER para evaluar la trama de datos, un ejemplo de lo que veremos en él será una trama donde S indica START luego el siguiente valor es la dirección A significa ACK el siguiente valor es el dato, otra vez A y luego P que significa pusa.











https://images.ecency.com/p/3W72119s5BjW4PvRk9nXBzqrPWMsMTjNrXDPFFf12CAfRz5MY8jCm5vGDUj7o96hwAT3YCMBJgcTgcWmsqeuBbZL1YbmxtaV4gyfByenDkmAkgv6rkm9ZP.webp?format=webp&mode=fit



0
0
0.000
2 comments
avatar

Thanks for your contribution to the STEMsocial community. Feel free to join us on discord to get to know the rest of us!

Please consider delegating to the @stemsocial account (85% of the curation rewards are returned).

You may also include @stemsocial as a beneficiary of the rewards of this post to get a stronger support. 
 

0
0
0.000
avatar

Congratulations @electronico! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)

You distributed more than 5000 upvotes.
Your next target is to reach 6000 upvotes.

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

Check out our last posts:

Keep Hive Buzzing - Support our proposal!
Our Hive Power Delegations to the February PUM Winners
The Hive Gamification Proposal
0
0
0.000