Software apps and online services
So I was digging around some projects from the old academia days and came across this midterm project for a class. It's not the best written code (almost non-existent error handling, header files not utilized, etc.), but it's functional. It's also not that practical either since you can just attach the light sensor directly into the ESP8266 and leave out the TIVA-C; it's an academic exercise so it's okay I guess. Anyways, I thought it would be useful for other people to see an example of I2C and UART communication implemented on C/C++.
The goal of the project is to integrate a light sensor, TSL2591, and a WIFI module, ESP8266, to a microcontroller., TM4C123GXL. The microcontroller should be able to read the data coming from the light sensor then push the data to the WIFI module. The module then transfers the data either to a server or to the cloud. Basically it needs to do the following:
- Establish communication between the light sensor (TSL2591) and the microcontroller (TM4C123GXL)
- Establish communication between microcontroller (TM4C123GXL) and the WIFI module (ESP8266)
- Send data collected from the light sensor (TSL2591) to a cloud server (ThingSpeak.com)
The first part of the implementation is to define and set the variables for the TSL2591 and the ESP8266. Then subroutines are declared for each device to be used for the main function. The main function starts off with declaring TaskStatus boolean variable to be used as a check if the subroutine is still running. Next is declaring the clock and speed. For this project, the main oscillator 16MHz oscillator is used.
Up next is the initialization of he pins and routines. First, the LEDs are initialized by enabling the GPIOF and setting the PORT 1, 2, and 3 as output pins. The LED color dictates the state of the microcontroller:
- RED = initializing
- GREEN = ready to send
- BLUE = send success.
Second, initialize the timer function found in DelayTimer.c, which allows the use of delay DelayTimer.c uses TIMER5 to create a time delay in micro or milliseconds. This delay function is to be used throughout the main function.
To communicate with the light sensor, the TM4C123GXL I2C1 peripheral is enabled. This includes pin MUXing and the GPIO port A for the SCL and SDA pins to be used as shown in the schematic. The data rate is then set to 100kbps. Next is to access the device address, 0x29.
After finding the address to be accessed, the device ID register is checked and verified to make sure we're communicating properly:
In order to do this, I2C1_write is used where the command bit is given along with TSL2591 register to be accessed. Then I2C1_read is used to retrieve the data from device register into an array, temp_data. The device can then enabled by using the same function used in
I2CMasterSlaveAddrSet. This command is set to false in order tell the microcontroller which register data to use to write into the slave address.
I2CMasterDataPut then puts the command bits into the register.
I2CMasterControl, finally, sends the data.
The data is stored as two 16-bit values, one for each channel as shown in the table above. It is recommended that all four bytes are to be extracted in sequence to minimize error or skew between CH0 and CH1 data. This is used for the
getLuminosity function where
I2CMasterSlaveAddrSet again is used, except set to true, to read the TSL2591 data registers and placed into a 32-bit register named x and y. CH1 is first read then is shifted by 16 bits. CH0 is then read and placed into the register using the bitwise OR operation. The data within the register can be processed using the equations found in the TSL2561 (chip equivalent to TSL2591) data sheet. The raw data can finally be converted to full-spectrum, infrared, and visible data.
The second task is to establish communication with the WIFI module (ESP8266) using the UART serial communication. As usual, peripherals need to be enabled such as the GPIOs and UARTs.
This includes configuring the pins, clock, and baud rate to match both devices. Once the connection is initialized and established, it will then be possible for the microcontroller (TM4C123GXL) to send and receive commands to the WIFI module (ESP8266) using AT commands. Each command is set into subroutine to easily be called and verified. The following are AT functions are called:
CIPCLOSEesp. These subroutines are used to get the microcontroller to connect to the wireless network. Each subroutine is labeled in the code and can be referenced as needed.
Now with the system set up, we can push the data from the light sensor to the WIFI module and into the ThingSpeak server IP and port. This is handled by
ProcessRoutine function. Here the data collected from the light sensor is printed to the command line screen every second as shown below.
Even though ThingSpeak can only receive data every 15 seconds, it is best to acquire data in between upload times to prevent fluctuating errors from drastic change in lighting. Collecting data while moving a light source in and out will show the graphs below.
Here's a demo video of the logger:
It basically shows the terminal output as it reads the TSL2591 light data and sends it to ThingSpeak. The data points on the graphs increases and decreases (as expected) as I move my lamp.
Looking back, finishing this midterm in time was frustrating and nerve-wracking. Things didn't really work, but one technique pulled me through: the Rubber Ducky Debugging method. This where you try to explain to a rubber duck your code and process, but I'm talking to my dog in my case. I'm sure he didn't understand anything but he helped a lot. Anyways, hopefully this write-up helps the same way. :]