In an earlier project I detailed an I2C (two-wire) interface to the common 1602 LCD. Recently I found a cheap 4-digit LED module that uses a pseudo I2C interface. I don’t have a particular need for it but I went ahead and added one to a parts order I made. If you know a little about I2C you know that it is a serial interface where the controlling circuit provides the clock and controls the direction of the single data line. Usually you can hang several I2C modules on the same pair of line (e.g.: clock module and display module) because each module has a unique address. I said this LED module has a “pseudo I2C” interface because it does not have an address. That means that it needs to be the only device using the data line.
LED I2C Module
The module I have is similar to the one shown here. It is typically listed as part number TM1637. You can find a variety of information on the web but I had a hard time finding all of the details I needed. I also looked at some existing code (Python and C) which can often be a dangerous thing to do. The one critical thing I determined from the code was that the data bits sent to the LED module need to be LSB first. That differed from the approach for the other I2C projects I have done. Another idiosyncrasy that I noted is that the addresses for the digits go from left to right (starting with address C0). That means that data must be written from most significant digit to least significant digit if using the auto increment addressing mode. In fixed addressing mode you would just pick the appropriate digit and write directly to it.
I2C communications are accomplished by using just two wires: one for data (SDA) and one for a clock (SCL). The data line is defined as being bidirectional so there needs to be a “master” device on the bus to control things. The clock rate is limited by the slowest device on the bus and controlled by the master device. Basically it sets a data bit and then toggles the clock line. At the end of each byte transfer the master reverses the direction of the data line and then clocks in the acknowledgement bit from the slave device.
There are three basic commands for the LED module. One controls the on/off and brightness of the display, one controls the address of the digit to write, and one controls the addressing mode (fixed or auto increment). Usually an application will just load all four digits each time so the auto increment mode is normally used and the address set to the first (left-most) digit.
The connections to the PIC are pretty simple with only two I/O pins being used. That leaves four other pins on our little 12F683 for getting sensor data. This same connection can be used with the 16F688 if we want more I/O pins. The module already has the required pull up resistors on the SDA and SCL lines.
The software link is listed below. While it is targeted for the 12F683, it is easily ported to bigger versions of the PIC like the pin compatible 16F688 that I use for a lot of my projects. Some of the newer PICs also have a hardware I2C interface so most of the related software routines would be greatly reduced or eliminated.
The I2C routines are the same as those I wrote for the LCD project but a lot of the other LCD-specific code was not needed for the LED module. I added a lookup table that converts single packed ASCII characters to the required LED segments. I also added a second test routine that shows how you can make non-ASCII displays by turning on the right segments. The data bit associations for the segments are shown in the header of the software source code. The eighth bit in the segment bytes is reserved for turning on the colon that resides between digits 2 and 3 on the module. In my tests it appeared that all four characters had to include a 1 in the eighth bit in order for the colon to light.
I added a line of code to the end of the “i2cwaitack”routine to try and recover if the slave does not acknowledge the data transfer. If the slave fails to acknowledge a transfer then the software will be reset by enabling the Watch Dog Timer (WDT). Newer PIC chips have a software reset command that can be used instead. An alternative for some I2C applications would be to simply make a call to “i2cstop” and then continue where the code left off. That’s it for this post. Check out my other electronics projects at boomerrules.com.