I have a plan to build a Nixie Clock so I search for its information and blog it here for further reference.
IN-16 may be not the smallest nixie tube but it's small enough to make a nice desk top nixie clock. The character height is about 13mm. I will use IN-16 for my upcoming nixie clock. There are some nixie clock kits that use IN-16 nixie tube so I am thinking about buying a kit or building it from scratch.
Saturday, November 22, 2008
The cheapest PIC with Internal Osc and I2C
I just got the above FM receiver module from SparkFun. It requires I2C interface. Actually, I2C can be implemented in software but I need I2C hardware so I can do something else in software. So, I went to microchip.com and searched for the cheapest PIC Microcontroller that comes with internal oscillator and I2C. Based on my search, PIC16F722 is the cheapest PIC with 16MHz internal osc. and I2C interface. Its price is $0.91 for 1000 pcs. I also found that PIC16F505 is the cheapest PIC that comes with internal oscillator (4MHz, $0.56/1000pcs.).
Anyway, I will develop my FM radio with PIC16F887 as I have it in hand.
Anyway, I will develop my FM radio with PIC16F887 as I have it in hand.
Topics:
FM Tuner,
Microcontroller
Wednesday, November 19, 2008
PCB for 7-Segment PIC Digital Clock
I have designed a single-sided PCB for the PIC Digital Clock. Because the autorouter is not good for routing single-sided PCB so I have to route by hand. It was my first hand routed PCB design and it was a time consuming task. I haven't tested the PCB yet. Use it by your own risk. I will produce this PCB and test it later.
As I don't have server to upload the Eagle file, please contact me if you want the file or PDF version of the image below.
Components side of the PCB. The red lines are jumpers.
As I don't have server to upload the Eagle file, please contact me if you want the file or PDF version of the image below.
Components side of the PCB. The red lines are jumpers.
Topics:
7-Segment,
Clock,
PCB,
PIC16F627a,
PIC16F628
Sunday, November 16, 2008
7-Segment PIC Digital Clock : The photographs
The prototype of the 7-Segment PIC Digital Clock. Check out 7-Segment Digital Clock for the schematic and source code.
Topics:
Clock,
Microcontroller,
PIC16F627a,
PIC16F628
Saturday, November 15, 2008
Using 11.2896 MHz with TMR1 (timer1 module)
A precision clock is my ultimate goal of making clocks. I know that cesium oscillator is to most precise clock on earth. However, a cesium clock is too expensive to play with. My option is using Rubidium oscillator which is the second most accurate oscillator after the cesium (I don't have reference about this) and its cost is more accessible. Searching on eBay about Rubidium Frequency Oscillator brought me to Ultra low jitter 11.2896Mhz Rubidium Frequency Clock . I am thinking about buying this item.
The question is 'How to make use of 11.2896 MHz frequency oscillator with my clock?'. If I run my MCU with this frequency, the internal frequency will be 11.2896MHz/4 = 2.8224 MHz. How to use this frequency to drive timer1 module for making a precision clock? TMR1 is a 16bit timer so it can count from 0 to 65535 before overflow. If I use TMR1 with this frequency without any setting, the TMR1 will send interrupt 2822400/65536= 43.06640625Hz or every 0.023219955 second which is unusable.
I have to find the initial value of the TMR1 for the best precision . The conditions are
1. The number of interrupts per second must be integer so I can count it precis
2. The initial value must be in form 0x##00. That means I have to set only the first 2 bits of TMR1 (TMR1H) as setting the lower bits takes some time and effects the clock precision.
The Solution
Expanding 2822400 results
2822400 = 256 x 49 x 25 x 9 = 57600 x 49
The meaning
If I set TMR1 to count upto 57600, it will send interrupt 49 times/second. Wow! It meets my first condition. To set TMR1 to count up to 57600, I have to set the initial value of TMR1 to 65536-57600 = 7936 = 0x1F00. Wow again!! It meets the second condition.
Now, I have to set TMR1H = 0x1F and count the number of interrupts to 49 to get 1 second time interval. Just perfect!
The question is 'How to make use of 11.2896 MHz frequency oscillator with my clock?'. If I run my MCU with this frequency, the internal frequency will be 11.2896MHz/4 = 2.8224 MHz. How to use this frequency to drive timer1 module for making a precision clock? TMR1 is a 16bit timer so it can count from 0 to 65535 before overflow. If I use TMR1 with this frequency without any setting, the TMR1 will send interrupt 2822400/65536= 43.06640625Hz or every 0.023219955 second which is unusable.
I have to find the initial value of the TMR1 for the best precision . The conditions are
1. The number of interrupts per second must be integer so I can count it precis
2. The initial value must be in form 0x##00. That means I have to set only the first 2 bits of TMR1 (TMR1H) as setting the lower bits takes some time and effects the clock precision.
The Solution
Expanding 2822400 results
2822400 = 256 x 49 x 25 x 9 = 57600 x 49
The meaning
If I set TMR1 to count upto 57600, it will send interrupt 49 times/second. Wow! It meets my first condition. To set TMR1 to count up to 57600, I have to set the initial value of TMR1 to 65536-57600 = 7936 = 0x1F00. Wow again!! It meets the second condition.
Now, I have to set TMR1H = 0x1F and count the number of interrupts to 49 to get 1 second time interval. Just perfect!
Topics:
Clock,
Microcontroller,
Oscillator
Thursday, November 13, 2008
Making a Digital Clock (Updated)
My fist Microcontroller project, PIC Digital Clock, is shown below.
I have added time setting feature to make it to be a usable clock. The updated version is shown below:
More features will be added in the future.
There is no fast or slow time setting as in normal/simple digital clocks. In this clock, each digit of the clock display can be set one by one via 2 setting buttons.
Features
1. Bright Led 7-Segment display without Multiplexing
2. Display: Hour, Minute, Second
3. Set time via 2 buttons
4. Set time Digit by Digit
5. Use internal oscillator of PIC16F627a or PIC16F628
6. Use 32.768KHz crystal for better clock accuracy
Setting Time:
1. The clock shows 12:34:56 when power the clock on. The first digit of hour (it's number 1 in this case) will be blinking to notify that the time is not correct and need to be set.
2. Press SET button to count up the digit.
3. Press MODE button when the digit is the correct time. The next digit will be blinking.
4. Repeat step 2 and 3 for setting minute and second.
5. Make sure that pressing MODE button for setting the second digit of second at the correct time.
Shecmatic of the Digital Clock
Example of a PCB design of the Digital Clock
The firmware ( source code in C ) written in MikroC
I don't have the picture of the prototype as I haven't made it yet. But I have tested the circuit and firmware with proteus already.
--- Update ---
- The prototype of this updated version is done. Please see its photographs at 7-Segment PIC Digital Clock : The photographs
- The PCB is ready: please check out PCB for PIC Digital Clock
I have added time setting feature to make it to be a usable clock. The updated version is shown below:
More features will be added in the future.
There is no fast or slow time setting as in normal/simple digital clocks. In this clock, each digit of the clock display can be set one by one via 2 setting buttons.
Features
1. Bright Led 7-Segment display without Multiplexing
2. Display: Hour, Minute, Second
3. Set time via 2 buttons
4. Set time Digit by Digit
5. Use internal oscillator of PIC16F627a or PIC16F628
6. Use 32.768KHz crystal for better clock accuracy
Setting Time:
1. The clock shows 12:34:56 when power the clock on. The first digit of hour (it's number 1 in this case) will be blinking to notify that the time is not correct and need to be set.
2. Press SET button to count up the digit.
3. Press MODE button when the digit is the correct time. The next digit will be blinking.
4. Repeat step 2 and 3 for setting minute and second.
5. Make sure that pressing MODE button for setting the second digit of second at the correct time.
Shecmatic of the Digital Clock
Example of a PCB design of the Digital Clock
The firmware ( source code in C ) written in MikroC
//6 digit clock
//Using timer1 16bit counter interrupt
// PIC16F627A or PIC16F628
// Internal Clock 4MHz
// PUNKKY@gmail.com
#define MODE PORTB.F4
#define SET PORTB.F5
#define Sec_port_l PORTA.F6
#define Sec_port_h PORTA.F4
#define Min_port_l PORTA.F3
#define Min_port_h PORTA.F2
#define Hr_port_l PORTA.F1
#define Hr_port_h PORTA.F0
#define Blink PORTA.F7
#define HTMR1 0x80
#define LTMR1 0x00
typedef unsigned short uns8;
uns8 i;
uns8 hr_h;
uns8 hr_l;
uns8 min_h;
uns8 min_l;
uns8 sec_h;
uns8 sec_l;
uns8 tick;
uns8 myTimer;
uns8 setting_time;
void setup ();
void set_time ();
void show_time ();
void display (uns8 digit);
void blink_digit (uns8 digit);
void check_bt ();
//void check_bt(); //chech button
void interrupt ()
{
PIR1.TMR1IF = 0;
// clears TMR1IF
TMR1H = HTMR1;
tick = 1;
Blink = 1;
sec_l ++;
if(sec_l>9){
sec_l = 0;
sec_h++;
}
if(sec_h>5){
sec_h=0;
min_l++;
}
if(min_l>9){
min_l = 0;
min_h++;
}
if(min_h>5){
min_h = 0;
hr_l++;
}
if(hr_l>9){
hr_l = 0;
hr_h++;
}
if(hr_h >2){
hr_h = 0;
}
if(hr_h >=2 && hr_l>3){
hr_h = 0;
hr_l = 0;
}
}
void main ()
{
setup ();
//Set time
hr_h = 1;
hr_l = 2;
min_h = 3;
min_l = 4;
sec_h = 5;
sec_l = 6;
show_time ();
setting_time = 1;
set_time();
while (1)
{
//blink_digit();
if (tick)
{
tick = 0;
show_time ();
Delay_ms (300);
Blink = 0;
}
check_bt ();
}
}
void setup ()
{
tick = 0;
//Digital output on PORTA
CMCON = 0x07;
//Input buttons + external clock
TRISB = 0xB0;
PORTB = 0x00;
TRISA = 0x00;
PORTA = 0x00;
//Internal Clock 4MHz
PCON.OSCF = 1;
// Prescaler 1:1 external clock
T1CON = 0x0F;
PIE1.TMR1IE = 0; // disable interupt to stop the clock
INTCON = 0xC0;
// Set GIE, PEIE
TMR1L = LTMR1;
TMR1H = HTMR1;
// TMR1 starts at 0x0BDC = 3036 to make TMR1 counts to 62500 and
// overclows in every 0.1 sec
// Math: 1/500000*8*62500 = 0.1
// 1/5000000 : time for 20MHz crystal (internal clock will be 20/4 = 5MHz)
// 8: prescaler
// 62500: TMR1 counts to 62500
// Counting number of overflows to 10 will get 1 sec.
}
void show_time ()
{
display (1);
display (2);
display (3);
display (4);
display (5);
display (6);
}
void display (uns8 digit)
{
switch (digit)
{
case 1 :
PORTB = hr_h;
Hr_port_h = 1;
Hr_port_h = 0;
break;
case 2 :
PORTB = hr_l;
Hr_port_l = 1;
Hr_port_l = 0;
break;
case 3 :
PORTB = min_h;
Min_port_h = 1;
Min_port_h = 0;
break;
case 4 :
PORTB = min_l;
Min_port_l = 1;
Min_port_l = 0;
break;
case 5 :
PORTB = sec_h;
Sec_port_h = 1;
Sec_port_h = 0;
break;
case 6 :
PORTB = sec_l;
Sec_port_l = 1;
Sec_port_l = 0;
break;
}
}
void blink_digit (uns8 digit)
{
switch (digit)
{
case 1 :
PORTB = 0xFF;
Hr_port_h = 1;
Hr_port_h = 0;
Delay_ms (100);
display (1);
Delay_ms (100);
break;
case 2 :
PORTB = 0xFF;
Hr_port_l = 1;
Hr_port_l = 0;
Delay_ms (100);
display (2);
Delay_ms (100);
break;
case 3 :
PORTB = 0xFF;
Min_port_h = 1;
Min_port_h = 0;
Delay_ms (100);
display (3);
Delay_ms (100);
break;
case 4 :
PORTB = 0xFF;
Min_port_l = 1;
Min_port_l = 0;
Delay_ms (100);
display (4);
Delay_ms (100);
break;
case 5 :
PORTB = 0xFF;
Sec_port_h = 1;
Sec_port_h = 0;
Delay_ms (100);
display (5);
Delay_ms (100);
break;
case 6 :
PORTB = 0xFF;
Sec_port_l = 1;
Sec_port_l = 0;
Delay_ms (100);
display (6);
Delay_ms (100);
break;
}
}
void set_time ()
{
i = 1;
while (setting_time)
{
blink_digit (i);
while (SET == 0)
{
Delay_ms (5);
switch (i)
{
case 1 :
hr_h ++;
if (hr_h > 2)
{
hr_h = 0;
}
break;
case 2 :
hr_l ++;
if (hr_l > 9)
{
hr_l = 0;
}
if (hr_h >= 2 && hr_l > 3)
{
hr_l = 0;
}
break;
case 3 :
min_h ++;
if (min_h > 5)
{
min_h = 0;
}
break;
case 4 :
min_l ++;
if (min_l > 9)
{
min_l = 0;
}
break;
case 5 :
sec_h ++;
if (sec_h > 5)
{
sec_h = 0;
}
break;
case 6 :
sec_l ++;
if (sec_l > 9)
{
sec_l = 0;
}
break;
}
while (SET == 0)
{
Delay_ms (5);
}
}
while (MODE == 0)
{
Delay_ms (5);
i ++;
if (i > 6)
{
sec_l--;
TMR1H = 0x80;
TMR1L = 0x00;
PIE1.TMR1IE = 1;
setting_time = 0;
break;
}
while (MODE == 0)
{
Delay_ms (5);
}
}
}
}
void check_bt ()
{
myTimer = 0;
if (setting_time == 0)
{
while (MODE == 0)
{
Delay_ms (5);
myTimer ++;
if (myTimer > 200)
{
setting_time = 1;
myTimer = 0;
break;
}
}
}
while (MODE == 0)
{
PIE1.TMR1IE = 0;
//Stop clock
Delay_ms (5);
blink_digit (1);
}
set_time ();
}
//Using timer1 16bit counter interrupt
// PIC16F627A or PIC16F628
// Internal Clock 4MHz
// PUNKKY@gmail.com
#define MODE PORTB.F4
#define SET PORTB.F5
#define Sec_port_l PORTA.F6
#define Sec_port_h PORTA.F4
#define Min_port_l PORTA.F3
#define Min_port_h PORTA.F2
#define Hr_port_l PORTA.F1
#define Hr_port_h PORTA.F0
#define Blink PORTA.F7
#define HTMR1 0x80
#define LTMR1 0x00
typedef unsigned short uns8;
uns8 i;
uns8 hr_h;
uns8 hr_l;
uns8 min_h;
uns8 min_l;
uns8 sec_h;
uns8 sec_l;
uns8 tick;
uns8 myTimer;
uns8 setting_time;
void setup ();
void set_time ();
void show_time ();
void display (uns8 digit);
void blink_digit (uns8 digit);
void check_bt ();
//void check_bt(); //chech button
void interrupt ()
{
PIR1.TMR1IF = 0;
// clears TMR1IF
TMR1H = HTMR1;
tick = 1;
Blink = 1;
sec_l ++;
if(sec_l>9){
sec_l = 0;
sec_h++;
}
if(sec_h>5){
sec_h=0;
min_l++;
}
if(min_l>9){
min_l = 0;
min_h++;
}
if(min_h>5){
min_h = 0;
hr_l++;
}
if(hr_l>9){
hr_l = 0;
hr_h++;
}
if(hr_h >2){
hr_h = 0;
}
if(hr_h >=2 && hr_l>3){
hr_h = 0;
hr_l = 0;
}
}
void main ()
{
setup ();
//Set time
hr_h = 1;
hr_l = 2;
min_h = 3;
min_l = 4;
sec_h = 5;
sec_l = 6;
show_time ();
setting_time = 1;
set_time();
while (1)
{
//blink_digit();
if (tick)
{
tick = 0;
show_time ();
Delay_ms (300);
Blink = 0;
}
check_bt ();
}
}
void setup ()
{
tick = 0;
//Digital output on PORTA
CMCON = 0x07;
//Input buttons + external clock
TRISB = 0xB0;
PORTB = 0x00;
TRISA = 0x00;
PORTA = 0x00;
//Internal Clock 4MHz
PCON.OSCF = 1;
// Prescaler 1:1 external clock
T1CON = 0x0F;
PIE1.TMR1IE = 0; // disable interupt to stop the clock
INTCON = 0xC0;
// Set GIE, PEIE
TMR1L = LTMR1;
TMR1H = HTMR1;
// TMR1 starts at 0x0BDC = 3036 to make TMR1 counts to 62500 and
// overclows in every 0.1 sec
// Math: 1/500000*8*62500 = 0.1
// 1/5000000 : time for 20MHz crystal (internal clock will be 20/4 = 5MHz)
// 8: prescaler
// 62500: TMR1 counts to 62500
// Counting number of overflows to 10 will get 1 sec.
}
void show_time ()
{
display (1);
display (2);
display (3);
display (4);
display (5);
display (6);
}
void display (uns8 digit)
{
switch (digit)
{
case 1 :
PORTB = hr_h;
Hr_port_h = 1;
Hr_port_h = 0;
break;
case 2 :
PORTB = hr_l;
Hr_port_l = 1;
Hr_port_l = 0;
break;
case 3 :
PORTB = min_h;
Min_port_h = 1;
Min_port_h = 0;
break;
case 4 :
PORTB = min_l;
Min_port_l = 1;
Min_port_l = 0;
break;
case 5 :
PORTB = sec_h;
Sec_port_h = 1;
Sec_port_h = 0;
break;
case 6 :
PORTB = sec_l;
Sec_port_l = 1;
Sec_port_l = 0;
break;
}
}
void blink_digit (uns8 digit)
{
switch (digit)
{
case 1 :
PORTB = 0xFF;
Hr_port_h = 1;
Hr_port_h = 0;
Delay_ms (100);
display (1);
Delay_ms (100);
break;
case 2 :
PORTB = 0xFF;
Hr_port_l = 1;
Hr_port_l = 0;
Delay_ms (100);
display (2);
Delay_ms (100);
break;
case 3 :
PORTB = 0xFF;
Min_port_h = 1;
Min_port_h = 0;
Delay_ms (100);
display (3);
Delay_ms (100);
break;
case 4 :
PORTB = 0xFF;
Min_port_l = 1;
Min_port_l = 0;
Delay_ms (100);
display (4);
Delay_ms (100);
break;
case 5 :
PORTB = 0xFF;
Sec_port_h = 1;
Sec_port_h = 0;
Delay_ms (100);
display (5);
Delay_ms (100);
break;
case 6 :
PORTB = 0xFF;
Sec_port_l = 1;
Sec_port_l = 0;
Delay_ms (100);
display (6);
Delay_ms (100);
break;
}
}
void set_time ()
{
i = 1;
while (setting_time)
{
blink_digit (i);
while (SET == 0)
{
Delay_ms (5);
switch (i)
{
case 1 :
hr_h ++;
if (hr_h > 2)
{
hr_h = 0;
}
break;
case 2 :
hr_l ++;
if (hr_l > 9)
{
hr_l = 0;
}
if (hr_h >= 2 && hr_l > 3)
{
hr_l = 0;
}
break;
case 3 :
min_h ++;
if (min_h > 5)
{
min_h = 0;
}
break;
case 4 :
min_l ++;
if (min_l > 9)
{
min_l = 0;
}
break;
case 5 :
sec_h ++;
if (sec_h > 5)
{
sec_h = 0;
}
break;
case 6 :
sec_l ++;
if (sec_l > 9)
{
sec_l = 0;
}
break;
}
while (SET == 0)
{
Delay_ms (5);
}
}
while (MODE == 0)
{
Delay_ms (5);
i ++;
if (i > 6)
{
sec_l--;
TMR1H = 0x80;
TMR1L = 0x00;
PIE1.TMR1IE = 1;
setting_time = 0;
break;
}
while (MODE == 0)
{
Delay_ms (5);
}
}
}
}
void check_bt ()
{
myTimer = 0;
if (setting_time == 0)
{
while (MODE == 0)
{
Delay_ms (5);
myTimer ++;
if (myTimer > 200)
{
setting_time = 1;
myTimer = 0;
break;
}
}
}
while (MODE == 0)
{
PIE1.TMR1IE = 0;
//Stop clock
Delay_ms (5);
blink_digit (1);
}
set_time ();
}
I don't have the picture of the prototype as I haven't made it yet. But I have tested the circuit and firmware with proteus already.
--- Update ---
- The prototype of this updated version is done. Please see its photographs at 7-Segment PIC Digital Clock : The photographs
- The PCB is ready: please check out PCB for PIC Digital Clock
Topics:
Clock,
MikroC,
PIC16F627a,
PIC16F628,
Source Code
Thursday, November 6, 2008
10-Second Counter
I have made a 10-Second Counter by using a PIC16F627a and a CD4543 BCD to 7-Segment decoder. This circuit and source code are just a demonstration of using MCU to drive an LED 7-Segment Display via CD4543. The 7-Segment displays from 0 to 9 and the number will roll over to 0 again. The interval between change is 1 second. So, this circuit counts 10 seconds between the roll over. I use TIMER1 module and 32.768KHz crystal to make 1 second timebase (see Clock with 32.768KHz Crystal for more info ).
The schematic of the 10-Second counter
Project setting of MikroC for using internal oscillator of the PIC16f627a.
The firmware is written in MikroC and you can find it below.
//PIC16F627A
//4MHz Internal OSC
// One Digit Counter
// 06/11/2008
//Punkky
unsigned short counter;
unsigned short tick;
void interrupt ()
{
PIR1.TMR1IF = 0; // clears TMR1IF
TMR1H = 0x80;
tick = 1;
}
void main(){
CMCON = 0x07; //Digital I/O for PORTA
TRISA = 0x00;
PORTA = 0x00;
TRISB = 0x00;
PORTB = 0x00;
T1CON = 0x0F;
// Prescaler 1:1 external clock
PIE1.TMR1IE = 1; // enable interupt to start the clock
INTCON = 0xC0; // Set GIE, PEIE
TMR1L = 0x00;
TMR1H = 0x80;
PCON.OSCF = 1; //Internal Clock 4MHz
//PCON.OSCF = 0; //Internal Clock 48KHz doesn't work well
counter = 0;
tick = 0;
PORTA.F0 = 1; // Enable 4345 BCD to 7-Segment
while(1){
if(tick){
tick = 0;
counter++;
PORTB = counter;
if(counter>9){
counter = 0;
}
}
}
}
The schematic of the 10-Second counter
Project setting of MikroC for using internal oscillator of the PIC16f627a.
The firmware is written in MikroC and you can find it below.
//PIC16F627A
//4MHz Internal OSC
// One Digit Counter
// 06/11/2008
//Punkky
unsigned short counter;
unsigned short tick;
void interrupt ()
{
PIR1.TMR1IF = 0; // clears TMR1IF
TMR1H = 0x80;
tick = 1;
}
void main(){
CMCON = 0x07; //Digital I/O for PORTA
TRISA = 0x00;
PORTA = 0x00;
TRISB = 0x00;
PORTB = 0x00;
T1CON = 0x0F;
// Prescaler 1:1 external clock
PIE1.TMR1IE = 1; // enable interupt to start the clock
INTCON = 0xC0; // Set GIE, PEIE
TMR1L = 0x00;
TMR1H = 0x80;
PCON.OSCF = 1; //Internal Clock 4MHz
//PCON.OSCF = 0; //Internal Clock 48KHz doesn't work well
counter = 0;
tick = 0;
PORTA.F0 = 1; // Enable 4345 BCD to 7-Segment
while(1){
if(tick){
tick = 0;
counter++;
PORTB = counter;
if(counter>9){
counter = 0;
}
}
}
}
Topics:
7-Segment,
Microcontroller,
MikroC,
PIC16F627a,
PIC16F628,
Schematic,
Source Code
Subscribe to:
Posts (Atom)