Sunday, September 28, 2008
Led Dot Matrix Scrolling Sign
Starting from the 5x7 led dot matrix clock, now, the Led Dot Matrix is one of my favorite topics for my projects. I have some led dot matrix projects in progress. They are all watch/clock related projects. Now, I am thinking that using led dot matrix to display only numbers is just a waste. A scrolling sign would be a nice project to utilize all of the power of led dot matrix. The above photo is a Mini Scrolling LED Sign. It's available as a kit from ElectronicKits.com. I think it's a great kit to start with. This scrolling sign has 96 different characters, and can store messages up to 80 characters long.
Topics:
Dot Matrix,
Microcontroller
Friday, September 26, 2008
Source Code for one chip 5x7 led dot matrix clock
As promised, listed below is the source code in MikroC for the 5x7 Led Dot Matrix Clock. The free demo version of MikroC can compile this code without any problem. Of course, the code is just for educational purpose only and use it with your own risk. The explanation about the source code will come later.
Setting time
- Press and hold MODE button until the digits blink
- The blinking digits are the hour is being set
- Press SET button to count up the hour
- When get the right hour, press MODE button to confirm hour setting
- Now the minute digits are blinking and ready to be set
- Press SET button to count up the minute
- When get the right minute, press MODE button to confirm minute setting and the second will be set to 0 automatically
- Now, the clock is set and the clock is running
Have fun!!!
Next improvements:
1. Using DS1307 as the time base will improve the clock accuracy and backup battery is also a nice feature of the DS1307
2. Dot matrix will be scanned and updated via interrupt routine to give the PIC more free time for doing something else
== Updated on 29 Nov 2009 ===
This firmware is written for The 5x7 Dot matrix Cathode Row. If you use Anode Row you have to make change to make_dotmatrix() by inverting the output PORTB and PORTD
===========================
Setting time
- Press and hold MODE button until the digits blink
- The blinking digits are the hour is being set
- Press SET button to count up the hour
- When get the right hour, press MODE button to confirm hour setting
- Now the minute digits are blinking and ready to be set
- Press SET button to count up the minute
- When get the right minute, press MODE button to confirm minute setting and the second will be set to 0 automatically
- Now, the clock is set and the clock is running
Have fun!!!
Next improvements:
1. Using DS1307 as the time base will improve the clock accuracy and backup battery is also a nice feature of the DS1307
2. Dot matrix will be scanned and updated via interrupt routine to give the PIC more free time for doing something else
== Updated on 29 Nov 2009 ===
This firmware is written for The 5x7 Dot matrix Cathode Row. If you use Anode Row you have to make change to make_dotmatrix() by inverting the output PORTB and PORTD
===========================
//One 5x7 Led Dot Matrix Clock
// PIC16F887
// I will use DS1307 as the RTC for the next improvement
// punkky@gmail.com
// 26 Sep 2008
#define MYMODE PORTA.F0
#define SET PORTA.F1
//External OSC 32.768KHz
#define HTMR1 0x80
#define LTMR1 0x00
//Constants for 4MHz Internal Clock
#define PAUSE_TIME 40
#define SCROLL_TIME_DELAY 60
#define HM_PAUSE_TIME 8
#define DTime 200
//Cursor Positions
#define HR_H_POS 0
#define HR_L_POS 0
#define DOT_1_POS 32
#define MIN_H_POS 12
#define MIN_L_POS 12
#define DOT_2_POS 56
#define SEC_H_POS 64
#define SEC_L_POS 72
//5x7 font
//Vertical scan , Little endian order
const unsigned char char2[][4]={
{0x1F,0x11,0x1F,0x00}, //0
{0x09,0x1F,0x01,0x00},
{0x17,0x15,0x1D,0x00},
{0x11,0x15,0x1F,0x00},
{0x1C,0x04,0x1F,0x00},
{0x1D,0x15,0x17,0x00},
{0x1F,0x15,0x17,0x00},
{0x10,0x10,0x1F,0x00},
{0x1F,0x15,0x1F,0x00},
{0x1D,0x15,0x1F,0x00}, //9
{0x0E,0x0E,0x0E,0x00}, //Comma1
{0x04,0x0E,0x04,0x00} //Comma2
};
unsigned char output[8];
unsigned char data[40];
unsigned char ptr;
unsigned char base_ptr;
unsigned char result_ptr;
unsigned char pp;
unsigned char pause_cnt;
unsigned char hr_pause_cnt;
unsigned char min_pause_cnt;
unsigned short counter;
unsigned short sec_h;
unsigned short sec_l;
unsigned short min_h;
unsigned short min_l;
unsigned short hr_h;
unsigned short hr_l;
unsigned short tick;
unsigned short num;
unsigned short i;
unsigned short j;
unsigned short time[8];
unsigned short setting_time;
unsigned short change_MYMODE;
void check_bt();
void button_fn(unsigned short param1, unsigned short pos1, unsigned short pos2);
void make_dotmatrix();
void interrupt() { //Internal clock
PIR1.TMR1IF = 0; // clears TMR1IF
TMR1H = HTMR1; //Set only high byte
tick = 1; // increment counter
}
void update_time();
void make_time();
void fill_data();
void show_digit(unsigned short pos);
void scroll();
void pause_digit(unsigned short position,unsigned short pause_delay);
unsigned short shift_register;
void main(){
setting_time = 0;
change_MYMODE = 0;
ANSEL = 0x00; //Digital I/O for PORTA
TRISA = 0x03;
PORTA = 0x03;
TRISB = 0x00;
PORTB = 0xFF;
TRISC = 0x0E;
TRISD = 0x00;
PORTD = 0x00;
ANSELH = 0x00; //Digital Input for PORTB
OSCCON = 0x65 ; //pic16f887 : 0110 0101, Internal Osc at 4MHz for lowest power consumption
counter = 0;
shift_register = 0x01;
hr_h = 1;
hr_l = 2;
min_h = 3;
min_l =4;
sec_h = 0;
sec_l = 0;
tick = 0;
fill_data();
pause_cnt =0;
hr_pause_cnt = 0;
min_pause_cnt = 0;
//TMR1 setup
T1CON = 0x8F; // 887 TMR1 Prescaler 1:1 external clock
INTCON = 0xC0; // Set GIE, PEIE
TMR1H = 0x80;
TMR1L = 0x00;
Delay_ms(10); // Delay for setting up TMR1
PIE1.TMR1IE = 1; // enable interupt
tick =0;
while(1){
scroll();
}
}
void show_digit(unsigned short pos){
for(i=0;i<8;i++){
output[i] = data[i+pos];
}
}
void update_time(){
if(tick){
tick =0;
sec_l++;
make_time();
fill_data();
}
}
void make_time(){
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;
if(setting_time == 0){
min_h++;
}
}
if(min_h>5){
min_h = 0;
if(setting_time == 0){
hr_l++;
}
}
if(hr_l>9){
hr_l = 0;
if(setting_time == 0){
hr_h++;
}
}
if(hr_h >2){
hr_h = 0;
}
if(hr_h >=2 && hr_l>3){
if(setting_time == 0){
hr_h = 0;
}
hr_l = 0;
}
}
void fill_data(){
time[0] = hr_h;
time[1] = hr_l;
time[2] = 10;
time[3] = min_h;
time[4] = min_l;
time[5] = 11;
time[6] = sec_h;
time[7] = sec_l;
for(i = 0;i<8;i++){
for(j=0;j<4;j++){
data[j+4*i] = char2[time[i]][j];
}
}
}
void button_fn(unsigned short param1, unsigned short pos1, unsigned short pos2){
for(;;){
if(SET == 0){
Delay_ms(10);
while(SET == 0);
Delay_ms(10);
switch (param1){
case 1: hr_h++; break;
case 2: hr_l++; break;
case 3: min_h++;break;
case 4: min_l++;break;
}
make_time();
fill_data();
show_digit(pos1);
}
if(MYMODE == 0){
Delay_ms(10);
while(MYMODE == 0);
Delay_ms(10);
if( param1 == 4){
setting_time = 0;
ptr = 0;
base_ptr = 0;
}else{
show_digit(pos2);
}
break;
}
make_dotmatrix();
Delay_ms(1);
}
}
void check_bt(){
while(MYMODE == 0){
Delay_ms(10);
for(i=0;i<100;i++){
for(j=0;j<10;j++){
make_dotmatrix();
Delay_ms(1);
if(MYMODE != 0){
setting_time = 0;
change_MYMODE = 1;
break;
}
}
}
while(MYMODE == 0){ // Set Hr high
setting_time = 1;
show_digit(HR_H_POS);
make_dotmatrix();
}
if(change_MYMODE){
ptr=8;
base_ptr = 0;
change_MYMODE = 0;
}
}
if(setting_time){
INTCON.GIE = 0 ; //Stop time counting
button_fn(1, HR_H_POS, HR_L_POS);
button_fn(2, HR_L_POS, MIN_H_POS);
button_fn(3, MIN_H_POS, MIN_L_POS);
button_fn(4, MIN_L_POS, 0);
//Reset timer1
TMR1L = LTMR1;
TMR1H = HTMR1;
INTCON.GIE = 1 ; // start clock
sec_l =0;
sec_h =0;
tick=0;
make_time();
fill_data();
}
}
void pause_digit(unsigned short position, unsigned short pause_delay){
if(base_ptr == position){
if(pause_cnt<pause_delay){
base_ptr--;
pause_cnt++;
}else{
base_ptr = position+1;
pause_cnt=0;
}
}
}
void scroll(){
ptr = 0; //start pointer
base_ptr = 0;
while(base_ptr<41){
result_ptr = (base_ptr+ptr)%40;
output[ptr] = data[result_ptr];
ptr++;
if(ptr == 8){
ptr = 0;
base_ptr++;
//Sec pause
pause_digit(25,PAUSE_TIME);
//Min pause
pause_digit(13,HM_PAUSE_TIME);
//Hr pause
pause_digit(1,HM_PAUSE_TIME);
}
for(pp=0;pp<SCROLL_TIME_DELAY;pp++){
update_time();
make_dotmatrix();
}
update_time();
check_bt();
make_dotmatrix();
}
}
void make_dotmatrix(){
if(counter == 7){
PORTB = output[counter]; //sent font data to PORTB
Delay_us(DTime);
PORTB = 0x00; //Turn off dots
shift_register = 0x01;
PORTD = ~shift_register; //sent scan data to PORTD
counter = 0;
} else{
PORTB = output[counter];
Delay_us(DTime);
PORTB = 0x00; //Turn off dots
shift_register = shift_register << 1;
PORTD = ~shift_register;
counter++;
}
}
// PIC16F887
// I will use DS1307 as the RTC for the next improvement
// punkky@gmail.com
// 26 Sep 2008
#define MYMODE PORTA.F0
#define SET PORTA.F1
//External OSC 32.768KHz
#define HTMR1 0x80
#define LTMR1 0x00
//Constants for 4MHz Internal Clock
#define PAUSE_TIME 40
#define SCROLL_TIME_DELAY 60
#define HM_PAUSE_TIME 8
#define DTime 200
//Cursor Positions
#define HR_H_POS 0
#define HR_L_POS 0
#define DOT_1_POS 32
#define MIN_H_POS 12
#define MIN_L_POS 12
#define DOT_2_POS 56
#define SEC_H_POS 64
#define SEC_L_POS 72
//5x7 font
//Vertical scan , Little endian order
const unsigned char char2[][4]={
{0x1F,0x11,0x1F,0x00}, //0
{0x09,0x1F,0x01,0x00},
{0x17,0x15,0x1D,0x00},
{0x11,0x15,0x1F,0x00},
{0x1C,0x04,0x1F,0x00},
{0x1D,0x15,0x17,0x00},
{0x1F,0x15,0x17,0x00},
{0x10,0x10,0x1F,0x00},
{0x1F,0x15,0x1F,0x00},
{0x1D,0x15,0x1F,0x00}, //9
{0x0E,0x0E,0x0E,0x00}, //Comma1
{0x04,0x0E,0x04,0x00} //Comma2
};
unsigned char output[8];
unsigned char data[40];
unsigned char ptr;
unsigned char base_ptr;
unsigned char result_ptr;
unsigned char pp;
unsigned char pause_cnt;
unsigned char hr_pause_cnt;
unsigned char min_pause_cnt;
unsigned short counter;
unsigned short sec_h;
unsigned short sec_l;
unsigned short min_h;
unsigned short min_l;
unsigned short hr_h;
unsigned short hr_l;
unsigned short tick;
unsigned short num;
unsigned short i;
unsigned short j;
unsigned short time[8];
unsigned short setting_time;
unsigned short change_MYMODE;
void check_bt();
void button_fn(unsigned short param1, unsigned short pos1, unsigned short pos2);
void make_dotmatrix();
void interrupt() { //Internal clock
PIR1.TMR1IF = 0; // clears TMR1IF
TMR1H = HTMR1; //Set only high byte
tick = 1; // increment counter
}
void update_time();
void make_time();
void fill_data();
void show_digit(unsigned short pos);
void scroll();
void pause_digit(unsigned short position,unsigned short pause_delay);
unsigned short shift_register;
void main(){
setting_time = 0;
change_MYMODE = 0;
ANSEL = 0x00; //Digital I/O for PORTA
TRISA = 0x03;
PORTA = 0x03;
TRISB = 0x00;
PORTB = 0xFF;
TRISC = 0x0E;
TRISD = 0x00;
PORTD = 0x00;
ANSELH = 0x00; //Digital Input for PORTB
OSCCON = 0x65 ; //pic16f887 : 0110 0101, Internal Osc at 4MHz for lowest power consumption
counter = 0;
shift_register = 0x01;
hr_h = 1;
hr_l = 2;
min_h = 3;
min_l =4;
sec_h = 0;
sec_l = 0;
tick = 0;
fill_data();
pause_cnt =0;
hr_pause_cnt = 0;
min_pause_cnt = 0;
//TMR1 setup
T1CON = 0x8F; // 887 TMR1 Prescaler 1:1 external clock
INTCON = 0xC0; // Set GIE, PEIE
TMR1H = 0x80;
TMR1L = 0x00;
Delay_ms(10); // Delay for setting up TMR1
PIE1.TMR1IE = 1; // enable interupt
tick =0;
while(1){
scroll();
}
}
void show_digit(unsigned short pos){
for(i=0;i<8;i++){
output[i] = data[i+pos];
}
}
void update_time(){
if(tick){
tick =0;
sec_l++;
make_time();
fill_data();
}
}
void make_time(){
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;
if(setting_time == 0){
min_h++;
}
}
if(min_h>5){
min_h = 0;
if(setting_time == 0){
hr_l++;
}
}
if(hr_l>9){
hr_l = 0;
if(setting_time == 0){
hr_h++;
}
}
if(hr_h >2){
hr_h = 0;
}
if(hr_h >=2 && hr_l>3){
if(setting_time == 0){
hr_h = 0;
}
hr_l = 0;
}
}
void fill_data(){
time[0] = hr_h;
time[1] = hr_l;
time[2] = 10;
time[3] = min_h;
time[4] = min_l;
time[5] = 11;
time[6] = sec_h;
time[7] = sec_l;
for(i = 0;i<8;i++){
for(j=0;j<4;j++){
data[j+4*i] = char2[time[i]][j];
}
}
}
void button_fn(unsigned short param1, unsigned short pos1, unsigned short pos2){
for(;;){
if(SET == 0){
Delay_ms(10);
while(SET == 0);
Delay_ms(10);
switch (param1){
case 1: hr_h++; break;
case 2: hr_l++; break;
case 3: min_h++;break;
case 4: min_l++;break;
}
make_time();
fill_data();
show_digit(pos1);
}
if(MYMODE == 0){
Delay_ms(10);
while(MYMODE == 0);
Delay_ms(10);
if( param1 == 4){
setting_time = 0;
ptr = 0;
base_ptr = 0;
}else{
show_digit(pos2);
}
break;
}
make_dotmatrix();
Delay_ms(1);
}
}
void check_bt(){
while(MYMODE == 0){
Delay_ms(10);
for(i=0;i<100;i++){
for(j=0;j<10;j++){
make_dotmatrix();
Delay_ms(1);
if(MYMODE != 0){
setting_time = 0;
change_MYMODE = 1;
break;
}
}
}
while(MYMODE == 0){ // Set Hr high
setting_time = 1;
show_digit(HR_H_POS);
make_dotmatrix();
}
if(change_MYMODE){
ptr=8;
base_ptr = 0;
change_MYMODE = 0;
}
}
if(setting_time){
INTCON.GIE = 0 ; //Stop time counting
button_fn(1, HR_H_POS, HR_L_POS);
button_fn(2, HR_L_POS, MIN_H_POS);
button_fn(3, MIN_H_POS, MIN_L_POS);
button_fn(4, MIN_L_POS, 0);
//Reset timer1
TMR1L = LTMR1;
TMR1H = HTMR1;
INTCON.GIE = 1 ; // start clock
sec_l =0;
sec_h =0;
tick=0;
make_time();
fill_data();
}
}
void pause_digit(unsigned short position, unsigned short pause_delay){
if(base_ptr == position){
if(pause_cnt<pause_delay){
base_ptr--;
pause_cnt++;
}else{
base_ptr = position+1;
pause_cnt=0;
}
}
}
void scroll(){
ptr = 0; //start pointer
base_ptr = 0;
while(base_ptr<41){
result_ptr = (base_ptr+ptr)%40;
output[ptr] = data[result_ptr];
ptr++;
if(ptr == 8){
ptr = 0;
base_ptr++;
//Sec pause
pause_digit(25,PAUSE_TIME);
//Min pause
pause_digit(13,HM_PAUSE_TIME);
//Hr pause
pause_digit(1,HM_PAUSE_TIME);
}
for(pp=0;pp<SCROLL_TIME_DELAY;pp++){
update_time();
make_dotmatrix();
}
update_time();
check_bt();
make_dotmatrix();
}
}
void make_dotmatrix(){
if(counter == 7){
PORTB = output[counter]; //sent font data to PORTB
Delay_us(DTime);
PORTB = 0x00; //Turn off dots
shift_register = 0x01;
PORTD = ~shift_register; //sent scan data to PORTD
counter = 0;
} else{
PORTB = output[counter];
Delay_us(DTime);
PORTB = 0x00; //Turn off dots
shift_register = shift_register << 1;
PORTD = ~shift_register;
counter++;
}
}
Topics:
Clock,
Dot Matrix,
Microcontroller,
MikroC,
Source Code
Tuesday, September 16, 2008
Schematic of the 5x7 Led Dot Matrix Clock
The above image is the schematic of the 5x7 led dot matrix digital clock. It includes a custom made component in Eagle, small 5x7 led dot matrix. However, this schematic is also working for any size of the 5x7 led dot matrix.I will post the detail about the firmware later.
-- updated 29 Nov 2009 ---
There is an error in the schematic, the MCU in the schematic is PIC16F887 (not PIC16F877)which has an internal oscillator so you don't need the external oscillator for the MCU. But you still need the 32.768 KHz for timebase.
Topics:
Clock,
Dot Matrix,
Microcontroller,
Schematic
Sunday, September 7, 2008
Just came back from Phuket
I arrived at my home about 24:04 last night, very tried.
Tonight, I have to work on an e-Marketplace report. I will be very busy in the next couple weeks so the detail about PIC projects will be posted after that.
Tonight, I have to work on an e-Marketplace report. I will be very busy in the next couple weeks so the detail about PIC projects will be posted after that.
Topics:
Trip
Subscribe to:
Posts (Atom)