понедельник, 27 января 2014 г.

Светодиодные часы

В этой статье рассказывается о том, как на основе ардуино сделать светодиодные часы. Статья содержит описание аппаратной части. Также приводится текст скетча, оживляющего все эти железки.


Для ардуино есть множество модулей с семисегментными светодиодными индикаторами. В своих часах я использовал модуль YwRobot представленный на картинке


В этом модуле использован четырехразрядный семисегментный светодиодный индикатор с общим анодом.

Ниже приведена схема подключения индикатора


Здесь нет ничего необычного. Это стандартная схема для подобных индикаторов.

Помимо индикатора модуль оснащен четырьмя кнопочками. Когда кнопочки не нажаты линии притянуты к VCC. Нажатие кнопочки прижимает связанную с ней линию к GND.

Этот модуль подключается к ардуино согласно приведенным ниже инструкциям

Arduino --- Led display

D0 --- dp
D1 --- g
D2 --- f
D3 --- e
D4 --- d
D5 --- c
D6 --- b
D7 --- a
D8 --- S4
D9 --- S3
D10 --- S2
D11 --- S1
A0 --- SW1
A1 --- SW2
A2 --- SW3
A3 --- SW4
5V --- VCC
GND --- GND

Еще в этом проекте используется модуль с переменным резистором. С его помощью осуществляется управление яркостью индикатора.


Этот модуль подключается к ардуино следующим образом

Arduino --- Variable Resistor

A4 --- OUT
5V --- VCC
GND --- GND

Вот и всё железо необходимое для реализации этого проекта. Описание аппаратной стороны закончено :)

Скетч для ардуино

////////////////////////
//
// Arduino
//
////////////////////////
//
// Sketch: led clock
//

const unsigned char DP = 0; // Digital Pin 0
const unsigned char G = 1; // Digital Pin 1
const unsigned char F = 2; // Digital Pin 2
const unsigned char E = 3; // Digital Pin 3
const unsigned char D = 4; // Digital Pin 4
const unsigned char C = 5; // Digital Pin 5
const unsigned char B = 6; // Digital Pin 6
const unsigned char A = 7; // Digital Pin 7

const unsigned char S4 = 8; // Digital Pin 8
const unsigned char S3 = 9; // Digital Pin 9
const unsigned char S2 = 10; // Digital Pin 10
const unsigned char S1 = 11; // Digital Pin 11

// Arduino Uno
//const unsigned char SW1 = 14; // Analog Pin 0
//const unsigned char SW2 = 15; // Analog Pin 1
//const unsigned char SW3 = 16; // Analog Pin 2
//const unsigned char SW4 = 17; // Analog Pin 3

// Arduino Leonardo
const unsigned char SW1 = 18; // Analog Pin 0
const unsigned char SW2 = 19; // Analog Pin 1
const unsigned char SW3 = 20; // Analog Pin 2
const unsigned char SW4 = 21; // Analog Pin 3

const unsigned char R = 4; // Analog Pin 4

const unsigned char N[10][7] =
{
{LOW, LOW, LOW, LOW, LOW, LOW, HIGH}, // 0
{HIGH, LOW, LOW, HIGH, HIGH, HIGH, HIGH}, // 1
{LOW, LOW, HIGH, LOW, LOW, HIGH, LOW}, // 2
{LOW, LOW, LOW, LOW, HIGH, HIGH, LOW}, // 3
{HIGH, LOW, LOW, HIGH, HIGH, LOW, LOW}, // 4
{LOW, HIGH, LOW, LOW, HIGH, LOW, LOW}, // 5
{LOW, HIGH, LOW, LOW, LOW, LOW, LOW}, // 6
{LOW, LOW, LOW, HIGH, HIGH, HIGH, HIGH}, // 7
{LOW, LOW, LOW, LOW, LOW, LOW, LOW}, // 8
{LOW, LOW, LOW, LOW, HIGH, LOW, LOW} // 9
};

unsigned int w1 = 8200;
unsigned int w2 = 0;

unsigned long int t1 = 0;
unsigned long int t2 = 1000;

unsigned char s = 0;
unsigned char m = 0;
unsigned char h = 0;

unsigned char p = HIGH;

void write_dig( unsigned char dig, unsigned char n, unsigned char dp )
{
    digitalWrite(A, N[n][0]);
    digitalWrite(B, N[n][1]);
    digitalWrite(C, N[n][2]);
    digitalWrite(D, N[n][3]);
    digitalWrite(E, N[n][4]);
    digitalWrite(F, N[n][5]);
    digitalWrite(G, N[n][6]);
    digitalWrite(DP, dp);

    digitalWrite(dig, LOW);
    for(int i = w1; i != 0; i -= 1) asm volatile("nop"::);

    digitalWrite(dig, HIGH);
    for(int i = w2; i != 0; i -= 1) asm volatile("nop"::);
}

void setup()
{
    pinMode(A, OUTPUT);
    pinMode(B, OUTPUT);
    pinMode(C, OUTPUT);
    pinMode(D, OUTPUT);
    pinMode(E, OUTPUT);
    pinMode(F, OUTPUT);
    pinMode(G, OUTPUT);
    pinMode(DP, OUTPUT);
    pinMode(S1, OUTPUT);
    pinMode(S2, OUTPUT);
    pinMode(S3, OUTPUT);
    pinMode(S4, OUTPUT);

    pinMode(SW1, INPUT);
    pinMode(SW2, INPUT);
    pinMode(SW3, INPUT);
    pinMode(SW4, INPUT);
}

void loop()
{
    t1 = millis();

    if ( (t1 / 1000) == (t2 / 1000) )
    {
        t2 += 1000;

        if ( digitalRead(SW1) == LOW ) { m += 1; s = 0; }
        if ( digitalRead(SW2) == LOW ) { m += 10; s = 0; }
        if ( digitalRead(SW3) == LOW ) { h += 1; s = 0; }
        if ( digitalRead(SW4) == LOW ) { h += 10; s = 0; }

        s += 1;

        if( s >= 60 ) { s = 0; m += 1; }
        if( m >= 60 ) { m = 0; h += 1; }
        if( h >= 24 ) { h = 0; }

        if ( p == HIGH ) { p = LOW; }
        else { p = HIGH; }
    }

    w1 = analogRead( R );
    w1 *= 8;
    w2 = 8200 - w1;

    write_dig(S1, (h / 10), HIGH);
    write_dig(S2, (h % 10), LOW);
    write_dig(S3, (m / 10), HIGH);
    write_dig(S4, (m % 10), p);
}

//
// End
//
////////////////////////

Приведенный скетч настроен на работу с Arduino Leonardo. Чтобы скетч работал с Arduino Uno, нужно раскомментировать код определяющий для этой платки константы SW1, SW2, SW3 и SW4. Также нужно закомментировать определение этих констант для Arduino Leonardo.

Питать часики лучше от блока питания или USB порта. Светодиодному индикатору нужно много тока. Батарейки менять замучаешься.

Сразу после включения на индикаторе будут ноли (полночь).

На часы и минуты отведено по две цифры. Разделителем служит точка.

Последняя точка включается и выключается каждую секунду. Функциональности никакой, но красиво.

Время устанавливается кнопками. В использованном модуле они аккуратно размещены под разрядами индикатора. Если нажать и держать кнопку, то цифра в соответствующем разряде увеличивается на единицу каждую секунду. Когда достигнуто необходимое значение, кнопка отпускается. Это самый простой и удобный способ.