Showing posts with label alarm clock. Show all posts
Showing posts with label alarm clock. Show all posts

Wednesday, 13 August 2014

Me, an Arduino and a DS3231 Real Time Clock


Check out the video above for a demonstration!

The grand project I am working on is a clock radio, and what good is it if it cannot accurately track time? It was tempting to try to set up the microcontroller to accurately track the time, but it would likely drift out fairly quickly. I decided that I would use an RTC (real time clock) module to keep track of the time for me. I looked around a little on google to see what others were using, and I looked around a little on eBay to see what was cheaply available and I settled on the DS3231. A few reasons for this:
  • Extremely accurate
  • Battery backup
  • I2C
  • Works with 5V
  • You can even get a temperature reading from it!
I purchased two units from eBay for $5.62US. Always buy at least two. If you wreck one, or one is broken then you don't need to wait - especially if ordering from China, you may need to wait 2-3 weeks to get your replacement!

They came in this nice static bag. On the bag it says "Raspberry Pi", which it seems like they were targeting this item to be sold to people who wanted to use it with the Pi, but it works just fine with any I2C capable device (I wonder if people looking for Arduino modules don't buy it because of the Raspberry Pi labeling?)





When you're looking around on the internet to buy these, it is important to remember that the DS3231 is the chip mounted on the board! They are not all created equal. This version only uses 4 pins - VCC, GND, SCL & SDA. It does deal with the battery on the board for you, which is nice, but you don't get a pin for reset, the 32KHz has an output on the chip as well as a pin for triggering an interrupt or sending out an adjustable square wave. If you want these features, you might want to see what other options are available for the DS3231.

It's sitting on a nice female header, which will make it easy to mount onto my perf board later. It came with that little battery - I doubt I'll ever replace it. It's everything I need, and more. I just wanted a 24 hour clock, this chip can track day, month, year and store 2 alarms.

Let's move onto the datasheet for this puppy, which can be found here: DS3231.pdf

It's only 20 pages, and a quick skim couldn't hurt. It picks up on page 11 when you get to see how the registers are formatted. It's all in BCD (binary coded decimal), so you need to work on the data before you send it out or display it - so '12' would be shown as '0001 0010' (I might do a video on bit manipulation, BCD and binary conversions some day). I'll attach some code to this blog entry, I feel it might be easier to see what's going on by looking at the code, rather than me try to explain it. The I2C is a little weird feeling on this, but I think I have a pretty good understanding after playing around with it for a little while.
I can try to save you some trouble with a mistake I made. They give an example of how to receive information from the data sheet - And no where in the data sheet do they tell you the address in plain English...
This might be my fault, but under slave address I was thinking a full byte had to be sent, but the 'slave address' was only 7 bits, so I put a '0' to the far right which I thought completed the 8 bits. So when I tried to address it, I was trying to talk to '0xD0', but for some reason you just read the 7 bits and imagine a zero as the MSB (most significant bit), which means the address was actually 0x68. Maybe if I spent more time playing with I2C devices this would have been more obvious? Who knows. I did learn something interesting from this: When I was trying to read data with the first address, I kept ending up with the retrieved bytes being 0xFF, which is all 1's in binary land, so for now on, if I'm working with I2C and I end up with nothing but 1's coming in the bytes, I'll assume either the address is wrong or the device is not connected - this could save troubleshooting time someday.
Moving along, I'm only really interested in the first 3 registers which handle the seconds, minutes and hours. I may yet do something with the temperature for fun.
You can look in the code to see the bit manipulation I used to extract the human readable numbers, it's quite easy once you get over the anxiety of dealing with thinking in binary.

One last hardware note: I'm holding up the lines to the 5V line with 4.7K resistors, with no issues.

Here's a picture of the Arduino board with the DS3231 module above. It ties on to the bus on the breadboard to the right, which also has the 4.7K resistors on it. The entire project is being powered by USB at this time.








This is the whole project with my radio portion (scroll down on the blog to learn more) TEA5767, the LM386, speaker, and of course, the DS3231.










For your viewing pleasure, another horrible paintbrush schematic! If you don't want the radio portion, you can ignore everything to the right of the DS3231 module.
The code includes the functions for the radio section. If you just wanted to use the getTime and initializeClock functions, you could cut and paste them - be sure to include the Wire.h header. Check back in the future to see this finished, the code will be more complete and I will have hopefully settled on how to have the user interact with it all.

#include <Wire.h>

unsigned char frequencyH;
unsigned char frequencyL;

unsigned int frequencyB;
double frequency;
double tunerFrequency;

unsigned int mainLoopCounter;

void setup()
{
  Wire.begin();
  frequency = 95.9; //A fancier approach would be to store this in EEPROM and retreive last channel ;)
  Serial.begin(9600);
  setFrequency();
  initializeClock(); //set the time in the initialize clock function and uncomment this line, upload,
                     //then comment this line out. It will retain your original time and not overwrite.
                     //A proper setting method will be incorporated later!
 
  Wire.beginTransmission (0x68); //if the clock isn't on register 0x00 at startup, it won't work properly
  Wire.write(0x00);
  Wire.endTransmission();
}

void loop()
{
  int reading = analogRead(0);
  //Serial.println(reading); //Shows the adc position - setting it to 512 will point "up" so you can attach a knob
  if (reading <= 410 || reading >= 614) checkTuner(); //only check tuning if tuning knob leaves rest area
 
  mainLoopCounter ++; //I know this is a little lame, won't be part of final
  if (mainLoopCounter == 2000)
  {
    getTime();
    Serial.println(frequency);
    mainLoopCounter = 0;
  }
}

void checkTuner()
{
  int currentReading = analogRead(0);
  if (currentReading <= 205) frequency = frequency--; //Tune back by 1MHz
  else if (currentReading >= 206 && currentReading <= 410) frequency = frequency - 0.1; //Tune back decimal
  else if (currentReading >= 614 && currentReading <= 819) frequency = frequency + 0.1; //Tune forward decimal
  else if (currentReading >= 820) frequency = frequency ++; //Tune forward by 1MHz
  else frequency = frequency; //If something unexpected happens, this will buffer it out
  if (frequency < 88.0) frequency = 88.0; //make sure it doesn't tune too low *Band limits can be adjusted
  if (frequency > 108.0) frequency = 108.0; //make sure it doesn't tune too high
  delay(300);// this delay will only occur if the main loop makes it into this function
  Serial.println(frequency);//only prints frequency while being tuned
  setFrequency();
}

void setFrequency()
{
  tunerFrequency = ((int)(frequency * 10)) / 10.0; //fun use of a cast!
  frequencyB = 4 * (tunerFrequency * 1000000 + 225000) / 32768;
  frequencyH = frequencyB >> 8;
  frequencyL = frequencyB;
  Wire.beginTransmission(0x60);
  Wire.write(frequencyH);
  Wire.write(frequencyL);
  Wire.write(0x1A);//0001 1010 -highside injection, forced mono, "right channel" muted, *PINOUT AND 3RD BYTE HAVE CHANNELS SWAPPED
  Wire.write(0x10);//Set for US and Europe band
  Wire.write(0x00);
  Wire.endTransmission();
}

void getTime()
{
  Wire.requestFrom(0x68,19,true); //its polling all 19 registers so it will be back to register 0x00 on next read.
  byte second = (Wire.read());
  byte minute = (Wire.read());
  byte hour = (Wire.read());
 
  //converting from BCD to decimal
  Serial.print(hour >> 4 & 0x03);
  Serial.print(hour & 0x0F);
  Serial.print(":");
  Serial.print(minute >> 4);
  Serial.print(minute & 0x0F);
  Serial.print(":");
  Serial.print(second >> 4);
  Serial.println(second & 0x0F);
}

void initializeClock()
{
   Wire.beginTransmission(0x68);
   Wire.write(0x00); //start at address 0x00
   Wire.write(0x00); //seconds - enter numbers how you would normally see them
   Wire.write(0x44); //minutes - these numbers would set the time to 22:44:00
   Wire.write(0x22); //hours (24h)
  //NOTICE: I only had to specify register once, it can increment the register on its own.
   Wire.endTransmission(); 
}


That's all I have to say about this for right now. Stay tuned to see what happens next. Hopefully this will help someone else working on something similar.

Good luck with your project!

Monday, 21 July 2014

TEA5767 FM Radio Receiver with Arduino and LM386 Amplifier

Moving along with the clock radio project, I made a hardware prototype of the radio component!

Here is the YouTube video that gives a quick demonstration and a quick overview:

See the second post on this topic for diagram and improved code: TEA5767 FM Radio Receiver with Arduino Part TWO

Basically, the goal of this was to get a radio module to work with a microcontroller, and also decide on the amplifier configuration. In the video you can see it hooked up to a small 8 ohm speaker, and it sounds decent - and it will sound better once it is in an enclosure.

I purchased new potentiometers, the TEA5767 modules and the LM386 amplifiers off of eBay. Waiting for the components is a little frustrating, however the venders in China are low cost and very friendly - I've only ever had one issue, and it was the mail systems fault.





The most difficult stage of the project was trying to get the TEA5767 module to be useable. It is really really small. Don't order just one of these, you will likely make a mistake - I bought two of them for less than $4.00.





Attaching wires to this was tricky. This was my first attempt. in the bottom left, you can see a surface mount component is missing.. while attaching the wire with a soldering iron, I accidentally had solder run up onto the board and the component started to float - it was way too small to re-attach. The device no longer functions correctly, maybe I'll try to figure out what the component was at some point and fix it, but for less than two bucks, I'll let it go. Another issues I had, and this happened on both my modules, the bottom right pin is VCC, and I accidentally bridged it to the case of the crystal, which caused a short - easily fixed.

The second attempt was a little more involved, but yielded much better results! I used a scrap of protoboard and some pin headers to hold the chip. This technique was very similar to what I think I say someone else do while I was looking around on Google (I forget where). Basically, I just used a small piece of wire and threaded it through and pushed it against the side of the board and I soldered it from the side so I wouldn't damage components. I pushed the plastic down on the pin headers to get as much length as possible on the pins and dripped the header in. The wires are tacked onto the pins on the backside NOTE: You will need a clamp of some sort to dissipate heat when soldering the wires to the pins, as the heat will otherwise separate your wire from the side of the chip (I used a set of self clamping tweezers). One of the reasons why my breadboard was such a mess was because it was built to hold my first attempt, and the 2nd attempt didn't fit quite so nicely.
The first attempt would have taken less space, the second attempt didn't fit on the breadboard very well. Since I only had two of these, this will be how the module exists in my final clock project.
Most of the information I gathered on using the TEA5767 with an Arduino was on another blog:
http://www.electronicsblog.net/arduino-fm-receiver-with-tea5767/
This blog contains lots of information, including some information from the datasheet, it's highly readable!


Also on the breadboard is the LM386 amplifier. The speaker and amplifier circuit are all running off of the 5v rail on the Arduino board, which also goes to show how little power this takes. The schematic I used I found on another blog, Hack A Week, which I follow on YouTube regularly. His LM386 blog is found here:
http://hackaweek.com/hacks/?p=131
The schematic shows a 10uf capacitor to optionally increase gain, this circuit had plenty of overhead without it, so I didn't include it. I did the "bass boost" filter, but used 0.047uf rather than 0.033uf - I personally liked the sound more.



Here is a picture of on of my Arduino development boards for fun. You can see I'm only using a few wires. The Arduino had two wires supplying power to the breadboard, 2 wires for the I2C and one wire to receive ADC (analog to digital data) from the potentiometer being used as the tuner.



So yeah, watch the video at the top to see what's going on here. In the near future, I hope to have the tubes soldered onto a board so I can start moving ahead with the build. I have a few concerns about trying to multiplex 6 tubes with the same microcontroller that is running devices on an I2C bus, I might use two...  I don't know, we'll see. But anyway, cheers!

Here's a picture of what this project is doing to my poor workbench. A mess is a sign of genius, right?
Good luck with your project!

Tuesday, 1 July 2014

IV-9 Clock - Prototyping!

IV-9 tubes are vintage Russian tubes which were a precursor to 7 segment LED displays. They are now sold on the internet along with other display tubes mostly for hobby applications. Most people are turning them into clocks, which I will also be doing - but I'm going to take it up a notch, and hopefully add a radio too!


Each of these tubes have 9 pins on them. 7 are for the segments, one is for a decimal place and the final pin is a common pin. I've decided to build my own hardware and to use a microcontroller to multiplex the tubes, or in other words, only one tube will be on at a time, and a different number pattern will be sent on the same data lines while a certain tube is selected. I did some research on this, and many people simplified (not necessarily a bad thing) their projects by using chips meant for driving LED 7 segment displays or using chips meant for building clocks.

Before I solder anything or get too far ahead of myself, I wanted to trouble shoot and sort out issues on a solderless bread board. I only put two tubes on, as these things take up a lot of space and use a lot of components. I'm also using an Arduino to speed up the prototyping. The final clock will hopefully be using a PIC18.


On this prototype all the inputs drive transistors, so the only component between the Arduino and the transistor base is a current limiting resistor. I'm using 2N3906 transistors for driving the characters, and 2N3904 on the tube selection (common pins on the tube).

I used 10K resistors on the base of the 2N3906's - they're only about 20mA's per segment.
I used 1K resistors on the base of the 2N3904's as the common pin on the tubes can possibly be handling each segments plus a decimal or roughly 160+mA.

The sad news is that I originally had segments from one tube bleeding into the same segment on the other tube, so I ended up installing diodes on each pin for each segment on each tube. 8 diodes a tube, I am not looking forward to soldering this board. It also drops the voltage down a bit, 5V-0.7V=4.3V, which is fine, the data sheet says a max of 4.5V anyway.

I would like to post a schematic, but I will need some serious time to figure out how to lay it out, things got pretty busy fairly quickly!


My 6 tube board will have the following materials:
6     IV-9 tubes
8     2N3906 Transistors
6     2N3904 Transistors
48   1N4007 Diodes
8     10K resistors
6     1K resistors

These parts were selected because I already had them, a lot of different variations could be used.


This code sample doesn't really have anything to do with what I'll have as a final product, I just used it for testing, but hopefully it will be of use to someone. Also - I was playing around with this, and stuffed some junk code in to simulate another 4 tubes being put in, and I had some stuttering issues, so I ended up completely removing the delays. I'm curious to see how changing the clock speed on my PIC18 will impact the tube intensity, which I have started porting this code over to it. Another concern I have is that when I have I2C devices attached, will they cause enough delay to stutter the tubes? I guess I'll find out!

/*
TEST SOFTWARE FOR 2 MULTIPLEXED IV-9 TUBES - REVISED
THIS IS TEST SOFTWARE AND WAS WRITTEN QUICKLY WITHOUT THE INTENT OF EXPANDING ON IT LATER,
IT IS NOT INTENDED AS A FINE CODING EXAMPLE.

JARRET CHESSELL
JULY 2nd 2014
http://awesomejarret.blogspot.ca/

OBJECTIVE IS TO TEST HARDWARE TO ENSURE OPERATION AND DEBUG HARDWARE
8 PNP 2N3906 TRANSISTORS ON CHARACTER BUS (ACTIVE LOW)
2 NPN 2N3904 TRANSISTORS ON TUBE SELECT BUS (ACTIVE HIGH)

*********************************************************************
DESCRIPTION:
WILL COUNT FROM 0-99 ON TWO IV-9 TUBES AT APPROX 1 SEC INTERVALS
COUNTER WILL ROLL OVER ONCE IT REACHES THE END.
BASICALLY A SUPER COMPLEX EGG TIMER
*********************************************************************

*/

//initialize an array which holds the patterns for numbers 0-9
byte numberPattern[] = {0x84, 0x9F, 0xA8, 0x89, 0x93, 0xC1, 0xC0, 0x8F, 0x80, 0x83, 0xFF};

//initialize counters to 0 with global scope
byte tensCounter = 0;//counts up for tube one
byte onesCounter = 0;//counts up for tube two
unsigned int loopCounter = 0; //delay counter

void setup() {
  //only thing done here is setting first ten pins to output and turning everything off
  PORTD = 0xFF; //PORTD is active low character bus -8bit
  PORTB = PORTB & 0xFC; //we're only manipulating the 2 lsb's, others are left unchanged
  for (byte i = 0; i < 10; i++){
    pinMode(i, 1);
  }
}

void loop() {
    if (loopCounter >= 500){ //chose 500, as each tube gets a 1ms delay, so should increment ~1sec
    loopCounter = 0;
    onesCounter++;
  }

  if (onesCounter >= 10) {
    onesCounter = 0;
    tensCounter++;
  }

  if (tensCounter >= 10) tensCounter = 0;

  PORTB = PORTB & 0xFC; //common pins off on both tubes
 
  PORTD = numberPattern[tensCounter]; //insert desired pattern and assign it to port
  PORTB = PORTB | 0x01; //"tens" tube common pin turned back on
  delay(1);
 
  PORTB = PORTB & 0xFC; // common pins off on both tubes
 
  PORTD = numberPattern[onesCounter];//insert desired pattern and assign it to port 
  PORTB = PORTB | 0x02; //"ones" tube common pin turned back on
  delay(1);
  loopCounter++;
}


In the YouTube video at the top I also gave mention to a website that I've ordered stuff from in the past, and many of the components I used I purchased from them. YourDuino.com I've used them more than once, and it's a cost effective away to bulk up your parts for prototyping!