Saturday, June 28, 2008

PIC16F887 is cheaper than PIC16F877A

I just realized that PIC16F887 (80 THB) costs less than half of PIC16F877A (200 THB).
The PIC16F887 is also comming with internal oscillators (8MHz, 32KHz). It's very nice for watch projects as it doesn't need external components.
After some searches, I have found a good info about PIC16F887 & PIC16F877A issue: Hello PIC16F887 MCUs- goodbye PIC16F877A! CCS News

From now on, I will use PIC16F887.

Saturday, June 14, 2008

Clock with 32.768KHz Crystal

I have learned from making a digital clock that setting TMR1L may apply some errors to the clock. As a solution, using a 32.768KHz crystal as an external oscillator will provide a better accuracy clock.
Why?
Because TMR1 with external osc. at 32.768KHz generates overflow interrupt every 2 seconds. If we set TMR1 to start at 0x8000 (32768), the TMR1 will overflow every 1 second!. Moreover, setting TMR1 to 0x8000 requires only TMR1H = 0x80 which does not affect the clock accuracy (setting TMR1L will affect the accuracy).

In my GPS clock, I am using PPS from GPS which is very accurate as an external oscillator. So, I don't need to use 32.768KHz crystal in my clock.

Making a Digital Clock

Please check the update at === Digital Clock Updated Version ===

--- Original Version ---
As I am a WIS so I built a clock as my first microcontroller project.

The clock is controlled by PIC16F628A from the PIC book . The idea was making a digital clock with hour, minute and second display. I just wanted to learn about microcontroller so the accuracy of the clock was not an issue (yet). However, I was trying to make it the most accurate as possible by using Timer1 Module of the PIC.

Timer1 Module (TMR1 Register)

The Timer1 Module is a 16 bit counter. It counts from 0x0000 to 0xFFFF and rolls over to 0x0000. The TMR1 interrupt is generated on overflow of the TMR1 register. More information about TMR1 is available in the data sheet of the PIC. In my clock, the PIC is running with 20MHz crystal so the internal clock is 5MHz. So, the duration between each TMR1 increment is 1/5000000 = 0.2 µs . That means TMR1 will overflow every 0.2 µs x 65536 = 0.0131072 s. If I count number of overflows to 77 times, I will get 1.0061744 s which is close to 1 second but the clock will gain about 6ms every second. The result will be a fast running clock (gaining about 9 min/day) .

To get a better accuracy, I make TMR1 counts to 62500 and set prescaler of the TMR1 to 1:8 (How these 62500 and 1:8 come? I did guess and test) . From these settings, the TMR1 will overflow every 1/5000000 x 8 x 62500 = 0.1 s. Counting number of overflows to 10 will yield 1 second. Just perfect huh!

Making Timer1 counts to 62500
It's easy. Just make it starts counting at 65536-62500 = 3036 = 0x0BDC by setting: (MikroC compiler)

TMR1L = 0xDC; //Write TMR1L first to reduce timing error.
TMR1H = 0x0B;

Setting TMR0 requires 2 clock cycles but I have no idea about how many cycles required for setting TMR1L. If 2 cycles were required for setting TMR1L, I should set TMR1L to 0xDC+2 = 0xDE so my clock will run more accurate. The frequency drift in the crystal is also a source of inaccuracy of the clock. The time drift from crystal can be calculated by using data from data sheet of the crystal. Normally, it says 20ppm (Part-Per-Million). That means the crystal will produce error about 20 s. in 1,000,000 s. or about 1.7 s./day.

Making prescaler 1:8
T1CON register contains TMR1 setting information. I set prescaler to 1:8 by

T1CON = 0x31;

Driving 7-segment leds
I don't multiplex the 7-segment leds, so I have to use 6 pieces of CD4543B to drive each 7-segment from BCD output of the PIC. As an outcome of non-multiplexing leds, I can get very bright display. Nearly all of the digital clock projects I have found on the Internet used 7447 or 4511 as the BCD 7-Segment decoders. I use CD4543B because it displays 6 and 9 with tails (nicer looking). However, I have seen some of 7447 and 4511 that also display 6 and 9 with tails but the data sheets of these ICs show 6 and 9 without tails.
number 9 without tailnumber 6 without tail6 and 9 without tails... I just don't like them :)






The schematic of the clock is very simple as shown in the image below (power supply of CD4345B doesn't show).
Schematic of the 7-segment Digital Clock
The working digital clock on protoboards.
Working digital clock on protoboards
Working digital clock on protoboards Missing things
- Buttons for setting time : The time is set by hard code in the program :) . Yeah, it's a very bad idea. But, I had a plan to get the time from GPS module so I didn't bother making those buttons. Now, my GPS clock is up and running.

- Alarm function: it's not alarm clock so there is no alarm function.

- Date: umm.. my GPS clock has it.

Saturday, June 7, 2008

DS1307 + PIC16F877A

DS1307 is a popular Real Time Clock (RTC) chip from MAXIM . Now, PIC16F877A is my favorite microcontroller. So, I was looking for information about interfacing DS1307 with PIC16F877A but I found only information in assembly language (assembly is not my cup of tea) and other C compilers. I use only mikroC. I adapted what I have found from the Internet. The source code is listed below:


//Sample code for
//DS1307 RTC Ineterfacing with PIC16F877A
//Coded by Pynn Pynn
//Compiler: mikroC 8.0.0
//http://picnote.blogspot.com
//07/06/2008
//Use with your own risk

unsigned short read_ds1307(unsigned short address );
unsigned short sec;
unsigned short minute;
unsigned short hour;
unsigned short day;
unsigned short date;
unsigned short month;
unsigned short year;
unsigned short data;
char time[9];
char ddate[11];

unsigned char BCD2UpperCh(unsigned char bcd);
unsigned char BCD2LowerCh(unsigned char bcd);

void main(){

I2C_Init(100000); //DS1307 I2C is running at 100KHz
PORTB = 0;
TRISB = 0; // Configure PORTB as output
TRISC = 0xFF;
Lcd_Init(&PORTB); // Initialize LCD connected to PORTB
Lcd_Cmd(Lcd_CLEAR); // Clear display
Lcd_Cmd(Lcd_CURSOR_OFF); // Turn cursor off
Lcd_Out(1, 1, "TIME:");
Lcd_Out(2, 1, "DATE:");

while(1)
{
sec=read_ds1307(0); // read second
minute=read_ds1307(1); // read minute
hour=read_ds1307(2); // read hour
day=read_ds1307(3); // read day
date=read_ds1307(4); // read date
month=read_ds1307(5); // read month
year=read_ds1307(6); // read year

time[0] = BCD2UpperCh(hour);
time[1] = BCD2LowerCh(hour);
time[2] = ':';
time[3] = BCD2UpperCh(minute);
time[4] = BCD2LowerCh(minute);
time[5] = ':';
time[6] = BCD2UpperCh(sec);
time[7] = BCD2LowerCh(sec);
time[8] = '\0';

ddate[0] = BCD2UpperCh(date);
ddate[1] = BCD2LowerCh(date);
ddate[2] ='/';
ddate[3] = BCD2UpperCh(month);
ddate[4] = BCD2LowerCh(month);
ddate[5] ='/';
ddate[6] = '2';
ddate[7] = '0';
ddate[8] = BCD2UpperCh(year);
ddate[9] = BCD2LowerCh(year);
ddate[10] = '\0';

Lcd_Out(1,6,time);
Lcd_Out(2,6,ddate);
Delay_ms(500);
}
}

unsigned short read_ds1307(unsigned short address)
{
I2C_Start();
I2C_Wr(0xd0); //address 0x68 followed by direction bit (0 for write, 1 for read) 0x68 followed by 0 --> 0xD0
I2C_Wr(address);
I2C_Repeated_Start();
I2C_Wr(0xd1); //0x68 followed by 1 --> 0xD1
data=I2C_Rd(0);
I2C_Stop();
return(data);
}


unsigned char BCD2UpperCh(unsigned char bcd)
{
return ((bcd >> 4) + '0');
}

unsigned char BCD2LowerCh(unsigned char bcd)
{
return ((bcd & 0x0F) + '0');
}


As I don't have DS1307 in hand, so I test my code with Proteus ISIS simulator. The image shows the working clock. Click on the image for big image.

Schematic of DS1307 and PIC16F877a or PIC16F887

Personal Reference

Items listed here are just for my own reference.
But it might be helpful when people google for these data.
1. DS1307 device address is 0x68 or 1101000
2. DS1307 works with I2C at 100KHz

Friday, June 6, 2008

CW25-TIM

CW25-TIM GPS Module
There is a limitation for my GPS clock. It needs clear view of the sky in order to get accurate time. I can get only 2 satellites if I put antenna close to window. So, I have to put the antenna outside my window to get more than 3 satellites.
Just now, I have found CW25-TIM from NavSync. From a note in the website, it reports that the CW25-TIM can get 9 satellites in a room without window!. Very impressive!

SemiconductorStore is selling it at USD64. I am thinking about using this GPS module for my GPS clock so the clock will be selfcontained, no need to put antenna outside building.
After some searches, I found that CW12-TIM is a ready-to-use GPS module that uses CW25-TIM inside. So, my target is now CW12-TIM.

Thursday, June 5, 2008

My GPS Clock is up and running

With the help of WDT, My GPS Clock is now running nicely. I don't know its exact accuracy. After comparing my GPS Clock time with SymmTime time, I can only say that my clock is very accurate. I use PIC16F877A to control the clock.

GPS Clock with LCD Display
I use PPS (Pulse Per Second) to drive my clock so ,theroticaly , the clock should be very accurate. The PPS accuracy from the Lassen iQ GPS module is about 50ns (when position fixes or SV>2).GPS Module
Next step, I will add sound of the second 'Tick' for accurately setting my watches. Also, I think that telling time with 7-Segment display should be more accurate than the LCD.

Pic Book

"PIC Microcontroller Learning By Doing" comes with handy components including PIC programmer and a PIC16F627A. Even protoboard and jumpers are also in the package. The protoboard and PIC16F27A and some components are now part of my digital clock so they are not in the picture.PIC Book
This is my only book about PIC. I bought it because I wanted the included components. I didn't have time to go to buy small components like resistors, leds, capacitors, blah blah.. . I just want everything for starting my project. About the content of the book, it is for beginners (I'm also a beginner). It provides you an idea how to work with the PIC microcontroller by using MicroC. It explains you how to control LED, PWM, motor, light sensor, input switch, thermometer and speaker. Not only the explanations, it also provides 20 projects inside the book, for example, timer, alarm, counter, music box etc., However, there is nothing about interrupt, PIC timer like TMR1. The projects are using plain flat C codes with Delay_ms() and Delay_us() functions.
All in all, I think it's worth my money (THB895, ~USD30).

Wednesday, June 4, 2008

Smallest 7-Segment Display

I have been looking for a small 7-Segment display for awhile. TDSG Series from VISHAY are among the smallest 7-Segment Displays I can find on the Internet. The character height is only 7mm. They are available at Mouser with mouser part # 78-TDSO1160 for common cathode and # 78-TDSO1150 for common anode. The price for one unit is $1.27. Actually, I found another small 7-Segment display, 7S-1 Super Tiny 7-Segment ($2.99). But, it is a vintage display (New Old Stock) so the reliability is questionable.

My first PCB design

Couple months ago, I tried my first PCB design with Cadsoft Eagle free version. The software is very easy to use and there are a lot of third party libraries available.
Below is my first design. It's the display board of my digital clock. The controller module is on another board. Anyway, the design may has to be changed in order to fit a plastic enclosure. Now, I am looking for a local PCB maker and a place to buy a plastic enclosure to realize my design.
7-Segment Digital Clock PCB

Tuesday, June 3, 2008

Laco Black Pilot Watch Limited 50 pcs.

Laco Black Pilot Watch Limited 50 pcs.Laco Black Pilot's Watch
Limited Edition 50 pieces world wide

Spec:

- Stainless Steel PVD case with 42 mm diameter
- B-Uhr (observers watch) dial
- Movement ETA 2824-2
- Big crown (bigger than showing in the photo)
- Domed Shappire Crystal
- Individual number on the case back
- Made in Germany
- Price: THB 32,500 or USD 1000 (Free shipping world wide)
- More information http://www.watchkzy.com/watch/laco/limited-black-pilot_english.html

My hero ... WDT: Watchdog Timer

I am now addicted to PIC Microcontroller projects. Last week, I just completed a prototype of my GPS controlled digital clock. The clock was running very nice and ,of course, it is one of the most accurate clock in the country :). I was very happy with it and thinking of putting more features to the clock. But... when I saw the clock this morning, I was shocked!. The clock was not running! it stopped last night around 00:23:xx . So, I pressed the reset button and the clock came back. Now, it is running happily (waiting for another Freeze in the future :p )

But, there are some questions. Why my clock stopped? Will it happend again? How to overcome the problem?. After google around, I think I found a potential answers to the questions. I was thinking that microcontrollers are just electronics devices that will work as they promise as long as you provide power to them. But, I was wrong. PIC Microcontrollers can Hang Up or Freeze just like your computers. So, my clock can Freeze just like my PC :) .

Will it happend again?
Yes, it will happend again but nobody knows when.

How to overcome the problem?
Now, the hero is WDT or Watchdog Timer. It just like a dog who keeps comming to see the PIC every certain period of time. If the PIC can kick the dog (by clearing WDT register with CLRWDT command), the dog will go back and will come to see the PIC again next time. But if the PIC cannot kick the dog (the PIC is engaging infinity loop or just freezing), the dog will reset the PIC. One nice thing is that you don't have to wait until the dog comes before you can can kick it. You can kick the dog anytime you want but you have to make sure that you kick it before it resets the PIC. By using WDT, I think I can make my clock running helthly without human reset when it hang up.

How to use WDT?
I am no expert on PIC. So, I will show what I did and explain what I understand.

  1. Set CONFIG word to enable WDT

  2. I use mikroC compiler, so I uncheck the default WDT_OFF = $3FFB and check _WDT_ON = $3FFF

  3. In the code I set up 2 functions: FeedDog() and KickDog()


  4. void FeedDog(){ //Setting WDT
    OPTION_REG = 0x0F; //0b00001111 = Prescalar 1:128 .. reset every 2.3 sec. please consult data sheet for other presacalars
    asm{CLRWDT} //Clear WDT
    }

    void KickDog(){
    asm{ CLRWDT } //Clear WDT before the dog resets the PIC
    }

  5. Placing FeedDog() and KickDog() in the main program

  6. I put FeedDog() around the begining of the program to set up WDT and put KickDog() wherever I think the dog will come. If the program is very long, I can put KickDog() in many places as I want if I think the dog will come after that line of code. It is upto me to calculate where to put the KickDog(). In my case, the dog keeps comming every 2.3 sec so I have to kick the dog before 2.3 sec after each kick. My clock update every second, so if it freeze and cannot kick the dog in 2.3 sec the PIC will be reset.
    Putting KickDog() in the wrong place can make your program running incorrectly. Please be careful.

    void main(){
    .. Set up program ..
    FeedDog();
    .. Set up some more things..

    while(1){
    ...
    .. Do tasks ..
    KickDog();
    ...Do tasks..
    ....
    }

    }


To be revised with images and more details