PIC 16F1827時計のソフトウエア開発 (9)

今回は、予告した秒針もどきの表示ルーチンについて、説明したいと思います。

 

SetLAT()とLEDset()という2つのルーチンを追加します。

/*
* item=0:0~5時のLED、1:6~11時とコロン
*
*/

void SetLAT(int item, unsigned int data) {

    LATA = ~((0x40 << item) | (data >> (item * 8) & 0x000f));
    LATB = ~((data >> (4 + item * 8)) & 0x000f) & (~MASKPB3) | (LATB & MASKPB3);
    //dataの上位4ビットを反転してPB3~0、PB7~4はHigh

    if (AlarmOn && item == 1) {
        //コロンを消灯してみる
        LATB2 = 1;
    }
}

/*
* 12+2個のLEDを光らせる
* item=0:0~5時のLED、1:6~11時とコロン
*/

int LEDset(int item, unsigned char data) {

    if (PatternMode & 0x0100) {
        if (LEDpatternAlarm[PatternPos] == 0xffff) PatternPos = 0;
        SetLAT(item, LEDpatternAlarm[PatternPos]);
        return;
    }

    switch (PatternMode) {
        case 1:
            if (LEDpattern1[PatternPos] == 0xffff) PatternPos = 0;
            SetLAT(item, LEDpattern1[PatternPos]);
            break;
        case 2:
            if (LEDpattern2[PatternPos] == 0xffff) PatternPos = 0;
            SetLAT(item, LEDpattern2[PatternPos]);
            break;
        case 3:
            if (LEDpattern3[PatternPos] == 0xffff) PatternPos = 0;
            SetLAT(item, LEDpattern3[PatternPos]);
            break;
        case 4:
            if (LEDpattern4[PatternPos] == 0xffff) PatternPos = 0;
            SetLAT(item, LEDpattern4[PatternPos]);
            break;
        default:
            //5秒間は、1つのLEDを点滅 
            if ((Bright[Pattern[1][Cnt]] & BrightPos) == 0) data = 0;
            //dataの下位4ビットと、itemで指定された上位を合わせて反転出力
            LATA = ~((0x40 << item) | (data & 0x0f));
            LATB = ~(data >> 4) & (~MASKPB3) | (LATB & MASKPB3); //dataの上位4ビットを反転してPB3~0、PB7~4はHigh
    if (AlarmOn && item == 1) {
        //コロンを消灯してみる
        LATB2 = 1;
    }
            break;
    }
}

SetLATは、LEDsetから呼び出されています。実際にPICのポートに出力しているルーチンとなります。

LEDsetは、周辺のLEDをどのように光らせるかの設定を行っています。

LED発光パターンとして、LEDpattern1~4、LEDpatternAlarmとか、Brigtという配列定数を使っています。

私の設定について、以下に示します。

 

//LEDの輝度
const unsigned int Bright[] = {
    0x0000, 0x0001, 0x0101, 0x0111,
    0x1111, 0x1115, 0x1515, 0x1555,
    0x5555, 0x5557, 0x5757, 0x5777,
    0x7777, 0x777f, 0x7f7f, 0x7fff,
    0xffff,
};


//LEDの発光パターン
const unsigned char Pattern[PatternMAX][10] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {16, 16, 16, 16, 8, 0, 0, 0, 0, 0},
    {16, 14, 13, 11, 10, 8, 6, 4, 2, 0},
    {0, 2, 4, 6, 8, 10, 11, 13, 14, 16},
    {16, 16, 16, 16, 16, 16, 16, 16, 16, 16},
};

//パターンの定義、0xffffで終端とするので、長さは任意でOK
//
//16bitのデータでLED0-11を光らせるパターンを設定。1で光る。
//bit 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
//LED -- -- 11 10  9  8  7  6  -  -  5  4  3  2  1  0 各時刻の所のLEDを示す
//注意:PatternPosのデータが

//振り子型のパターン
//2sで1周期
const unsigned int LEDpattern1[] = {
    //0s    0.1s    0.2s    0.3s    0.4s    0.5s    0.6s    0.7s    0.8s    0.9s
    0x0010, 0x0010, 0x0030, 0x0020, 0x0120, 0x0100, 0x0300, 0x0200, 0x0600, 0x0400,
    0x0400, 0x0400, 0x0600, 0x0200, 0x0300, 0x0100, 0x0120, 0x0020, 0x0030, 0x0010,
    0xffff,
};

//十字の位置の4LEDが回るように光るパターン
const unsigned int LEDpattern2[] = {
    //0s    0.1s    0.2s    0.3s    0.4s    0.5s    0.6s    0.7s    0.8s    0.9s
    0x0909, 0x0909, 0x0909, 0x0909, 0x0909, 0x1212, 0x1212, 0x1212, 0x1212, 0x1212,
    0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0xffff,
};

//上から下へ流れるように落ちるパターン
const unsigned int LEDpattern3[] = {
    //0s    0.1s    0.2s    0.3s    0.4s    0.5s    0.6s    0.7s    0.8s    0.9s
    0x0001, 0x2003, 0x2002, 0x3006, 0x1004, 0x180c, 0x0c18, 0x0630, 0x0320, 0x0100,
    0xffff,
};

//ぐるぐる回っているように光るパターン
const unsigned int LEDpattern4[] = {
    //0s    0.1s    0.2s    0.3s    0.4s    0.5s    0.6s    0.7s    0.8s    0.9s
    0x2001, 0x0003, 0x0006, 0x001c, 0x0030, 0x0120, 0x0300, 0x0600, 0x1c00, 0x3000,
    0xffff,
};

//アラーム用:十字の位置の4LEDが回るように光るパターン
const unsigned int LEDpatternAlarm[] = {
    //0s    0.1s    0.2s    0.3s    0.4s    0.5s    0.6s    0.7s    0.8s    0.9s
    0x0909, 0x0909, 0x1212, 0x1212, 0x2424, 0x2424, 0xffff,
};

 

最初のBrightとPatternは、秒針を示すための5回ずつ光らせるものです。
Patternが1秒間にどのような輝度で光らせるかを定義しており、0は消灯、16だと常に光らせるという感じにして、輝度を表現できるようにしています。Bright[]では、さらに短い時間で、1になっているビットなら点灯、0なら消灯で、Bright[16]は、0xffffなので、常に光らせることになり、Bright[4]なら、0x1111なので、2進数に直すと、0001 0001 0001 0001となり、4回に1回しか光らせません。

つまり、25%しか点灯しなくなるので、ダイナミック点灯しているLEDが暗く見えるようになることを期待しています。

 

ダイナミック点灯には、1ms毎の割り込みを使っています。10ms周期で、処理が1周するようにしています。今どのLED群を対象としているかを示している変数が、ScanTimer2です。

以下の表に示したような処理が行われます。

ScanTimer2 処理内容
0 周辺の0時~5時の部分の6つのLEDを点灯
1 周辺の6時~11時とコロンを加えた8つのLEDを点灯
2 時の1の位の7セグメントLEDを点灯
3 時の10の位の7セグメントLEDを点灯
4 分の1の位の7セグメントLEDを点灯
5 分の10の位の7セグメントLEDを点灯
6 ScanTimer2=2と同じ
7 ScanTimer2=3と同じ
8 ScanTimer2=4と同じ
9 ScanTimer2=5と同じ

周辺のLEDの方が輝度が高かったので、10回中1回だけ光らせ、7セグのLEDは、10回中2回光らせました。

先ほど説明した周辺のLEDの輝度は、この10msに1回光らせるのを毎回行うのを最大輝度として、16ビットの定数を使って、最小の輝度では、16回つまり160msに1回光らせられるようにしているのです。

 

これらを今までのソースに追加してコンパイルするのですが、少し待って下さい。そのままコンパイルしても、前と動作は変わりませんので。

LEDset()を呼び出す必要があります。main()内の無限ループしているルーチン内に、LEDsetをコメントアウトしている所が2か所あるはずです。ここを生かします。

具体的には、

修正前:

if (ScanTimer2 == 0) ;//LEDset(0, (1 << ss));
else if (ScanTimer2 == 1) ;//LEDset(1, (1 << (ss - 6)) | 0xc0);

修正後:

if (ScanTimer2 == 0) LEDset(0, (1 << ss));
else if (ScanTimer2 == 1) LEDset(1, (1 << (ss - 6)) | 0xc0);

として下さい。これで、コンパイルして、PIC時計に書き込みます。

 

さて、どういう動作になるかというと、通常は、5秒ずつ1つのLEDが点滅を繰り返します。

赤か白ボタンを押すと、そのパターンが変わります。

先ほど提示した配列定数は、LEDpattern1~4まで、4種類ありました。

1: 振り子のような表示

2: 十字の位置の4つのLEDが回転するパターン

3: 上から下へ流れるように落ちるパターン

4: 1秒で、1周、ぐるぐる回るように光るパターン

以上のような表示パターンを作ってみました。

動画を表示させるため、初めてユーチューブに登録してみました。

いかがでしょうか。映像編集が素人ですが、PIC時計がどのようにLEDを表示させているかの雰囲気を理解いただければよいので、ご容赦下さい。

今回は、これで終了とさせていただきます。

この記事へのコメント

この記事へのトラックバック