| Weitere Artikel aus dem Elo-Magazin |
LED Wordclock
Wie spät ist es? „ES IST FÜNF NACH ZWÖLF"
von Martin Steppuhn
Was man auf die einfache Frage nach der Uhrzeit als Antwort bekommt, lässt sich mit einer LED- und Buchstabenmatrix formschön und pfiffig als Uhr aufbauen. Das Retro-Spiel PING PONG enthält eine fertig bestückte Platine mit 120 LEDs und einem Atmel MEGA8 Mikrocontroller. Diese Platine eignet sich hervorragend und muss neben der Software lediglich um einen Uhrenquarz und einen Taster erweitert werden um diese Uhr zu realisieren.
| Ganzen Artikel lesen... | ![]() |

Zwischen K1 und K2 wird ein kleiner Taster gelötet und B6/B7 wird mit einem 32,768 kHz Uhrenquarz bestückt. (CKOPT Fuse setzen) Die Potis aus dem Original Bausatz werden nicht verwendet. Bereits mit einer gedruckten Papiermatrix lassen sich ganz ansehnliche Ergebnisse erzielen. Optimal wird es jedoch, wenn die LEDs durch einen Abstandshalter untereinander entkoppelt werden und das Licht durch einen Diffusor gestreut wird. Die Buchstabenmatrix wurde dann in eine spezielle Acrylglasscheibe gelasert.
Die Software ist in C geschrieben und liegt für den AVR-GCC als AVR-Studio Projekt hier zum Download bereit. Langes Drücken des Tasters führt in den Einstellmodus. Zuerst werden die Minuten eingestellt und nach dem zweiten langen Tastendruck die Stunden.
Download: wordclock_v1_0.zip
Originalartikel auf www.emsystech.de (Mit Kontaktformular des Autors für Fragen zu den verwendeten Folien)
Video auf Youtube
//------------------------------------------------------------------------------
// Filename: main.c
// Description: LED-Paint
//
//
// Copyright (c) Martin Steppuhn (www.emsystech.de)
//
// Nur für den privaten Gebrauch / NON-COMMERCIAL USE ONLY
//
// Die Nutzung (auch auszugsweise) ist für den privaten und nichtkommerziellen
// Gebrauch erlaubt. Eine Veröffentlichung und Weiterverwendung des Quellcodes
// ist möglich wenn diese Nutzungsbedingungen incl. Copyright beiliegen
// und die Quelle verlinkt ist. (www.emsystech.de)
//
// Bei kommerziellen Absichten nehmen Sie bitte Kontakt mit uns auf
// (info@emsystech.de)
//
// Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion. Benutzung
// auf eigene Gefahr. Es wird keinerlei Haftung für direkte oder indirekte
// Personen- oder Sachschäden übernommen.
//
// Author: Martin Steppuhn
// History: 18.12.2009 Initial version
//------------------------------------------------------------------------------
/**** Includes ****************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "std_c.h"
#include "uart.h"
/**** Preprocessing directives (#define) **************************************/
//=== Portpins ===
#define DATA_SET PORTB |= (1<<4)
#define DATA_CLR PORTB &= ~(1<<4)
#define CLK_SET PORTB |= (1<<3)
#define CLK_CLR PORTB &= ~(1<<3)
#define STROBE_SET PORTB |= (1<<2)
#define STROBE_CLR PORTB &= ~(1<<2)
#define BUTTON (!(PIND & (1<<2)))
//=== Pixels ===
#define CLEAR_ALL led[0]=0; led[1]=0; led[2]=0; led[3]=0; led[4]=0; led[5]=0; led[6]=0; led[7]=0; led[8]=0; led[9]=0; led[10]=0; led[11]=0
#define WORD_ES_IST led[0]|=1; led[1]|=1; led[4]|=1; led[5]|=1; led[6]|=1
#define WORD_ZEHN led[8]|=1; led[9]|=1; led[10]|=1; led[11]|=1
#define WORD_FUENF led[1]|=0x02; led[2]|=0x02; led[3]|=0x02; led[4]|=0x02
#define WORD_VOR_1 led[6]|=0x02; led[7]|=0x02; led[8]|=0x02
#define WORD_VIERTEL led[5]|=0x04; led[6]|=0x04; led[7]|=0x04; led[8]|=0x04; led[9]|=0x04; led[10]|=0x04; led[11]|=0x04
#define WORD_NACH led[0]|=0x08; led[1]|=0x08; led[2]|=0x08; led[3]|=0x08
#define WORD_VOR_2 led[4]|=0x08; led[5]|=0x08; led[6]|=0x08
#define WORD_HALB led[8]|=0x08; led[9]|=0x08; led[10]|=0x08; led[11]|=0x08
#define WORD_EMSYSTECH led[1]|=0x10; led[2]|=0x10; led[3]|=0x10; led[4]|=0x10; led[5]|=0x10; led[6]|=0x10; led[7]|=0x10; led[8]|=0x10; led[9]|=0x10
#define WORD_5 led[0]|=0x20; led[1]|=0x20; led[2]|=0x20; led[3]|=0x20
#define WORD_2 led[6]|=0x20; led[7]|=0x20; led[8]|=0x20; led[9]|=0x20
#define WORD_1 led[8]|=0x20; led[9]|=0x20; led[10]|=0x20; led[11]|=0x20
#define WORD_7 led[0]|=0x40; led[1]|=0x40; led[2]|=0x40; led[3]|=0x40; led[4]|=0x40; led[5]|=0x40
#define WORD_6 led[7]|=0x40; led[8]|=0x40; led[9]|=0x40; led[10]|=0x40; led[11]|=0x40
#define WORD_10 led[0]|=0x80; led[1]|=0x80; led[2]|=0x80; led[3]|=0x80
#define WORD_9 led[3]|=0x80; led[4]|=0x80; led[5]|=0x80; led[6]|=0x80
#define WORD_4 led[8]|=0x80; led[9]|=0x80; led[10]|=0x80; led[11]|=0x80
#define WORD_3 led[0]|=0x100; led[1]|=0x100; led[2]|=0x100; led[3]|=0x100
#define WORD_11 led[4]|=0x100; led[5]|=0x100; led[6]|=0x100
#define WORD_8 led[8]|=0x100; led[9]|=0x100; led[10]|=0x100; led[11]|=0x100
#define WORD_12 led[1]|=0x200; led[2]|=0x200; led[3]|=0x200; led[4]|=0x200; led[5]|=0x200
#define WORD_UHR led[9]|=0x200; led[10]|=0x200; led[11]|=0x200
#define WORD_FUNKUHR led[5]|=0x200; led[6]|=0x200; led[7]|=0x200; led[8]|=0x200; led[9]|=0x200; led[10]|=0x200; led[11]|=0x200
#define PIC_FRAME led[0] = 0x3FF; led[1] = 0x201; led[2]=0x201; led[3]=0x201; led[4]=0x201; led[5]=0x201; led[6]=0x201; led[7]=0x201; led[8]=0x201; led[9]=0x201; led[10]=0x201; led[11]=0x3FF
/**** Type definitions (typedef) **********************************************/
/**** Global constants ********************************************************/
/**** Global variables ********************************************************/
/**** Local constants ********************************************************/
const uint8 font[40] = // Digits
{
0xFE,0x82,0x82,0xFE, // 0
0x08,0x04,0xFE,0x00, // 1
0xC4,0xA2,0x92,0x8C, // 2
0x82,0x92,0x92,0x7C, // 3
0x1E,0x10,0xF8,0x10, // 4
0x9E,0x92,0x92,0x62, // 5
0x78,0x94,0x92,0x60, // 6
0x02,0xF2,0x0A,0x06, // 7
0xFE,0x92,0x92,0xFE, // 8
0x9E,0x92,0x92,0xFE // 9
};
/**** Local variables *********************************************************/
uint8 c;
uint16 led[12];
uint8 col_cnt;
uint16 col;
uint8 button_mem;
uint8 hour,minute,second;
uint8 time_setup;
uint8 time_setup_cnt0;
uint8 time_setup_cnt1;
uint16 loop_cnt;
uint8 sec_flag,key_flag;
/**** Local function prototypes ***********************************************/
//------------------------------------------------------------------------------
// Name: dram_time
// Function: Zeit entsprechend darstellen
//
// Parameter:
// Return:
//------------------------------------------------------------------------------
void draw_time(void)
{
uint8 i,h;
if(time_setup == 2)
{
i = (hour / 10) * 4;
led[0] = font[i];
led[1] = font[i+1];
led[2] = font[i+2];
led[3] = font[i+3];
led[4] = 0;
i = (hour % 10) * 4;
led[5] = font[i];
led[6] = font[i+1];
led[7] = font[i+2];
led[8] = font[i+3];
led[9] = 0;
if(second & 1) { led[10] = 0x44; led[11] = 0; }
else { led[10] = 0; led[11] = 0x44; }
}
else if(time_setup == 1)
{
if(second & 1) { led[0] = 0x44; led[1] = 0; }
else { led[0] = 0; led[1] = 0x44; }
led[2] = 0;
i = (minute / 10) * 4;
led[3] = font[i];
led[4] = font[i+1];
led[5] = font[i+2];
led[6] = font[i+3];
led[7] = 0;
i = (minute % 10) * 4;
led[8] = font[i];
led[9] = font[i+1];
led[10] = font[i+2];
led[11] = font[i+3];
}
else
{
CLEAR_ALL;
WORD_ES_IST;
WORD_UHR;
h = 0;
if( minute < 5) { h = hour; }
else if(minute < 10) { WORD_FUENF; WORD_NACH; h = hour; }
else if(minute < 15) { WORD_ZEHN; WORD_NACH; h = hour; }
else if(minute < 20) { WORD_VIERTEL; WORD_NACH; h = hour; }
else if(minute < 25) { WORD_ZEHN; WORD_VOR_1; WORD_HALB; h = hour + 1; }
else if(minute < 30) { WORD_FUENF; WORD_VOR_1; WORD_HALB; h = hour + 1; }
else if(minute < 35) { WORD_HALB; h = hour + 1; }
else if(minute < 40) { WORD_FUENF; WORD_NACH; WORD_HALB; h = hour + 1; }
else if(minute < 45) { WORD_ZEHN; WORD_NACH; WORD_HALB; h = hour + 1; }
else if(minute < 50) { WORD_VIERTEL; WORD_VOR_2; h = hour + 1; }
else if(minute < 55) { WORD_ZEHN; WORD_VOR_1; h = hour + 1; }
else if(minute < 60) { WORD_FUENF; WORD_VOR_1; h = hour + 1; }
if( h == 0) { WORD_12; }
else if(h == 1) { WORD_1; }
else if(h == 2) { WORD_2; }
else if(h == 3) { WORD_3; }
else if(h == 4) { WORD_4; }
else if(h == 5) { WORD_5; }
else if(h == 6) { WORD_6; }
else if(h == 7) { WORD_7; }
else if(h == 8) { WORD_8; }
else if(h == 9) { WORD_9; }
else if(h == 10) { WORD_10; }
else if(h == 11) { WORD_11; }
else if(h == 12) { WORD_12; }
}
}
//------------------------------------------------------------------------------
// MAIN
//------------------------------------------------------------------------------
int main(void)
{
DDRC = 0x0F;
DDRD = 0xF0;
DDRB = 0x03 + (1<<2) + (1<<3) + (1<<4);
PORTD |= (1<<2); // für Pullup
SFIOR &= (1<<PUD);
// Timer 2 mit externem 32kHz Quarz betreiben
ASSR |= (1<<AS2);
TCCR2 = (1<<CS22) + (1<<CS20); // /128 für 1Hz Int
// Timer 1 für LED INT mit ca. 1,2kHz
TCCR1A = 0;
TCCR1B = (1<<WGM12) + (1<<CS10);
OCR1A = 6667;
// Timer Interrupts
TIMSK = (1<<OCIE1A) + (1<<TOIE2); // set interrupt mask
uart_init();
uart_puts_p("\r\nWordClock V1.0.0, Dez.2009 Martin Steppuhn (www.emsystech.de)\r\n");
hour = 0;
minute = 0;
second = 0;
time_setup = 0;
sei(); // Interrupt ein
while(1)
{
if(sec_flag) //=== 1 Sekunde ===
{
sec_flag = false;
if(BUTTON)
{
time_setup_cnt1++;
if(time_setup_cnt1 > 3)
{
time_setup++;
if(time_setup > 2) time_setup = 0;
}
}
else
{
time_setup_cnt0++;
if(time_setup_cnt0 > 5) time_setup = 0;
}
draw_time();
}
if(key_flag) //=== 10ms ===
{
key_flag = false;
if(!BUTTON && button_mem) // falling Edge
{
button_mem = false;
if(time_setup == 1) minute = (minute<59) ?minute+1 : 0;
if(time_setup == 2) hour = (hour < 11) ? hour+1 : 0;
}
if(BUTTON)
{
button_mem = true;
time_setup_cnt0 = 0;
}
else
{
time_setup_cnt1 = 0;
}
draw_time();
}
// if(uart_kbhit()) { c = uart_getc(); uart_putc(c); }
}
}
//------------------------------------------------------------------------------
// Name: TIMER2_OVF_vect
// Function: TIMER2 Overflow mit 1Hz (32kHz Uhrenquarz /128 /256
//
// Parameter:
// Return:
//------------------------------------------------------------------------------
ISR(TIMER2_OVF_vect)
{
second++;
if(second > 59)
{
second=0;
minute++;
if(minute > 59)
{
minute = 0;
hour++;
if(hour > 11) hour = 0;
}
}
sec_flag = true;
}
//------------------------------------------------------------------------------
// Name: TIMER1_COMPA_vect
// Function: LED-Matrix Refresh mit 1,2kHz -> 100Hz Bildwiderholrate
//
// Parameter:
// Return:
//------------------------------------------------------------------------------
ISR(TIMER1_COMPA_vect)
{
col_cnt++;
if(col_cnt > 11)
{
key_flag = true; // zum sampeln/entprellen der Taste
col_cnt=0;
DATA_CLR;
}
else
{
DATA_SET;
}
CLK_SET;
CLK_CLR;
PORTC &= ~0x0F;
PORTD &= ~0xF0;
PORTB &= ~0x03;
STROBE_SET;
STROBE_CLR;
col = led[col_cnt];
PORTC |= col & 0x0F;
PORTD |= col & 0xF0;
PORTB |= (col >> 8) & 0x03;
}















