If you want to connect several I2C devices of the same type on the same bus, it is useful to have a simple routine to change the address of the slaves and avoid conflicts. In fact, in some cases it is possible to change the slave I2C address within a preset number of available numbers selectable by connecting via hardware particular pins, in other cases, as with the laser sensor used in our examples you have the freedom to set the address you want simply by writing it to a particular memory address. This procedure is mandatory at every start as the sensor loses the address when the power is removed.
Prepare the development environment as indicated in the following posts:
- PIC Microcontroller from scratch (for the scheme and setting of the system clock).
- A couple of words via RS232 (for serial settings).
- I2C detect (for setting the I2C bus).
Unlike previous posts we will use the RS232 in bidirectional way to have a console that allows us to insert the new I2C address to be assigned to the slave; to do this we will use the EUSART of the micro also in reception as well as in transmission as we have done up to now with the function prinf().
Having set the serial of the micro through the MCC tool, already exist the functions and the interrupts necessary to bidirectionally manage the communication, let's try to understand how the system works. Each bit received on the serial line generates an interrupt that is managed by the interrupt_manager.c file; at each received bit the manager calls the EUSART_Receive_ISR function present in the eusart.c file that queues the received bits into an 8-bit array called eusartRxBuffer and consequently increases the eusartRxCount variable that keeps the received bytes account. To read the received character we can use the function that is made available to us: EUSART_Read().
Those listed above are the variables and functions that we will use in our program to create the dialog with the user. Let's see a short extract:
During the dialog with the user via RS232 we go through various phases in which we expect certain answers. To take into account these phases we define the variable appStatus of type statuses whose value can be one of those listed in the image above. Each time a response is provided, using the switch construct, we set the status that allows the program to receive the next answer.
We have just seen that we have the EUSART_Read() function that allows us to read a byte (character) on the serial. We can do this every time that eusartRxCount is greater than zero:
We are interested in receiving a complete response from the user, that is when "enter" is pressed. Consequently the StringReceived() function is called at each cycle to read the user response one character at a time, when the LF character is received it means the string is complete and I can return true warning the caller that the answer is available in the buffer.
In the main cycle of the program (of which I report only one piece):
I read the answer string, I do a simple check on the length and type of character typed, then I import the value and set appStatus so that when the next string is received the program will evaluate a new data.
This is the execution of the program into terminal:
It is possible to download the entire project from github: download project