Hi all,
This is my first post over here, but I've been lurking around the forums for quite some time now. I'm new to electronics and recently started dabbling in it about 6 months ago. I've got a full time job, so this is pretty much a hobby for me. This post is for bragging as well as posting my findings over here for anyone who's interested.
Recently, I saw a video of the DotKlok and was inspired to make the same. So I got myself the DS1307 and started reading the datasheet. Didn't really understand much, but saw that it uses the I2C bus protocol to transfer data. So, started reading up on the I2C protocol and I found it very interesting. That, and other resources on the net, helped me understand how the I2C works and how to use it with the DS1307.
So I decided to try and implement the I2C bus manually without using the arduino library Wire.h. It seemed simple enough, you just need two lines which are turned high or low to communicate like Morse code (I told you, I'm not an electronics engineer!). I followed the circuit diagram given here and set it up. But it's annoying that there's really not much to find on the web for this when you're really stuck.
The toughest part, for me, was figuring how to turn the data and clock lines high and low! I2C requires the Data Line (SDA) and Clock Line (SCL) to be in high when idle. Any communication happens by pulling the lines to low. In PIC C code, this I suppose is done by setting SDA=0 and SCL=0. (Refer: I2C tutorial) But how do we do that here? SDA and SCL should not be made active HIGH by the microcontroller since that would cause Logic Contention in the circuit. Logic Contention, as I understand it, happens when you've got 2 devices bringing the line to high at the same time. It shows up in Proteus without which I wouldn't have been able to find the problem.
So after a lot of reading on the Arduino website, Googling around and experimenting with the board, I finally realised that I shouldn't raise the lines to high, but should rather let them float to high using the pullup resistors in the circuit. But how do I do that without setting the pins to Output? The answer is by setting the pins to Input. When you set the pin to input, it uses a very minuscule amount of current to detect whether the line is high or low without affecting the circuit, effectively not letting current pass through. So the line goes to high. And how do you make the line go Low? By setting the pin as output! The reason is that when you put the pin to output, it defaults to a Low which is ground. If the pin is grounded, it pretty much brings the line down i.e. low. This was the EUREKA moment for me :).
I've attached the code in it's entirety and it's working well with the DS1307. Couldn't paste it as it was exceeding the character limit. I'll be happy to get some input/improvements about the code or any advice/warnings/pitfalls about the way I've set it up. I haven't referred to Wire.h, so don't know if this is how it's done there as well.
EDIT: Updated the file for one error in handling 12hr/24hr modes
i2c_ds1307.ino (7.8 KB)