記事一覧

8ピンPICの比較

2009.06.25

秋月のHPより抜粋。8ピンPICの仕様比較です


 12F62912F67512F68312F615
動作電圧2.0V(4MHz)~
5.5V(20MHz)
2.0V(4MHz)~
5.5V(20MHz)
2.0V(4MHz)~
5.5V(20MHz)
2.0V(4MHz)~
5.5V(20MHz)
フラッシュ1Kワード1Kワード2Kワード1Kワード
RAM64バイト64バイト128バイト64バイト
EEPROM128バイト128バイト256バイト-
A/D-10Bit4ch10Bit4ch10Bit4ch
コンパレータ--1ch1ch
タイマ8ビット--22
タイマ16ビット--11
秋月定価\80\110\150\100

タグ:PIC 8ピン データシート

7セグLED時計の製作⑤

2009.06.24

今回の作品について振り返り、反省点など

  • タイマー割り込みで正確な1秒を得ようとしたが、なかなか上手くいかなかった。
    タイマー関連レジスタを変更するとばらつくということが後で分かりましたが、ここに気づくまでかなり苦労しました。
  • 初めての自作回路で7セグLEDを扱うのも初めてだったのですが、ピンアサインが少し変わっていて配線が大変でした。
  • LEDに多くのポートを取られたため、スイッチの2つはIn-Out兼用としました。この手法はどこかで使えると思います。
  • お気に入りは「エコモード」。4桁目のドット部だけが0.5秒おきに点滅して節電する仕様です。
  • 秋月の11.766MHzクリスタルは5個100円とお買い得でした。セラロック等では時計としての精度が出ないですが、クリスタルなら実用性十分です。
  • PicKit2でプログラムの書き換えをオンボードでやろうとすると電圧のエラーが出たが、回路に別電源を供給することで解消しました。
  • タグ:PIC 16F648A 7セグLED

    7セグLED時計の製作④

    2009.06.23

    一応完成

    7セグLED時計(完成)
    ブレッドボードから基盤へ配線し直し、ケース(フロッピーが5枚程度入ってた物)に収めました。
    電源は昔使っていたPHSの充電器(7.0V150mA)を3端子レギュレータ(78L05)に落として5Vを取り出し、ついでに動作確認用に青色LEDを付けたものを作成。


    フィルムのキャップをかぶせると暗闇で、ほんのり浮かび上がります。


    苦労したのはケースの加工です。
    押しボタン用のスイッチ穴を空けたのと、PicKitのICSP用ピンが干渉するので、その部分も削りました。
    また、固定用としてネジ15mm、スペーサ10mmを購入しましたが、ケースと基盤の厚みを考慮してなかったためナットが届かず・・・
    ステレンレスのスペーサを削るのも一仕事でした。

    タグ:PIC 16F648A 7セグLED

    7セグLED時計の製作③

    2009.06.12

    7セグLED時計のプログラムの説明です
    とりあえず動かすことを念頭に置いたプログラムなので、かなり雑だと思いますが・・・
    プログラムのポイントとなる部分だけを解説します。

    __CONFIG(UNPROTECT & LVPDIS & BORDIS & MCLREN & PWRTEN & WDTDIS & HS);
    __IDLOC(F648);

    static unsigned int watch, stp_watch; // ウオッチ WORK
    static long t_save, w_save; // 時計 WORK
    static unsigned char dg_f, dgt[4], dot[4], // 桁表示 WORK
    hh, mm, ss, // 時・分・秒
    dsp_mode, // 表示モード
    slp_on, wat_on; // スリープ、ウオッチ制御
    static const char dig[]; // 数字・文字パターン(後方参照の定義)


    冒頭の部分はコンフィグビットの設定と、グローバル変数の定義ですが、
    static const char dig[];
    の部分は、サイズ指定しない配列にC言語を見慣れない人には「?」と思われるかも知れませんが、実体をここでは定義せず、プログラムの後の方で定義する後方参照のための宣言です。
    少しだけプログラムを見やすくするためで、配列の中身は、プログラムの最後で定義しています。

    static const char dig[] ={        // 数字・文字定義(0がオン)
    0b11000000, //0
    0b11111001, //1
    0b10100100, //2
    0b10110000, //3

      (中略)

    0b11111111, //All Off
    0b10101011, //n
    0b11000111, //L
    0b10001100 //P
    };

    今回使った7セグLEDはアノードコモンと呼ばれるタイプで、回路の設計上「1」が消灯、「0」が点灯としています。
    数字の0-9以外はインデックスを定数宣言しています。

    #define DSP_DOT    16                      // LEDのドット
    #define DSP_OFF 17 // LED OFF
    #define DSP_n 18 // LEDのn文字
    #define DSP_L 19 // LEDのL文字
    #define DSP_P 20 // LEDのP文字

    ついでにポートの定義です。

    #define SWT_MODE    RA4                 // モードスイッチのポート
    #define SWT_1 RB2 // スイッチ1のポート
    #define SWT_2 RB3 // スイッチ2のポート
    #define TRIS_1 TRISB2 // スイッチ1の入力
    #define TRIS_2 TRISB3 // スイッチ2の入力

    では、プログラムのロジック部分です。
    disp()関数については、特に難しい部分はないと思います。
    PORTAにつながった1-4桁のアノードを順次オンにし、PORTBに表示したいセグメントを8ビットでオン・オフしています。
    時計のカウントは割り込処理で実行しています。
    static interrupt int_server(void)
    関数です。今回のプログラムではタイマ1(TMR1)をメインの時刻用にタイマ0(TMR0)はストップウオッチ等汎用のタイマーとして使用しています。
    TMR1の処理を解説します。

        if (TMR1IF) {                             // TMR1割込み
    TMR1IF = 0; // フラグクリア
    t_save += 0x10000; // TMR1の1週アップ分
    // if (t_save > 250000) { // 4MHZの場合の1秒
    if (t_save > 736000) { // 11.776MHzの場合の1秒
    ss++; // 1秒追加して
    t_save -= 736000; // 1秒分カウンタ差し引き
    if (ss >= 60){ // 60秒=1分
    mm++;
    ss=0;
    }
    if (mm >= 60) { // 60分=1時間
    hh++;
    mm=0;
    }
    if (hh >= 24) // 24時=0時
    hh = 0;
    }
    }

    PICで正確な1秒を得るには少々工夫が必要です。私も試行錯誤の末、下記の方法を採用しました。
    では、今回の回路では11.776MHzのクリスタルを使用しているので、それを前提に説明すると。
    TMR1がオーバーフローして割り込みが発生するということは、TMR1が65,536をカウントした時です。16進数では0x10000と表せます。
    では、1秒間にTMR1は幾つカウントが必要でしょうか?以下の式で求められます。
    11,776,000÷4÷4=736,000
    です。最初の「11,776,000」は水晶の周波数で、1秒間の発振数です。タイマは4クロックで1カウントですので、4で割ります。
    最後にプリスケーラーを「1:4」で設定しているので、4で割ります。
    1回の割り込み毎に65,536(0x10000)を足し、合計が736,000を超えたところで1秒をカウントします。この時、t_saveの値は736,000を超えているので、736,000を引き、余りを次の割り込みへのキャリーオーバーとします。
    ここで重要なことは、TMR1がオーバーフローして割り込みが発生した時に、タイマ関連のレジスタを触らないことです。
    最初、TMR1H、TMR1Lレジスタを弄くって0.1秒等キリのいい数字を得ようとしましたが、同じ周期で割り込みが発生せず相当悩みました。
    正確に同周期で割り込みを発生させるためには、TMR1H、TMR1LやTMR0のレジスタだけでなく、TMR1IEなどのビットも変更しないよう、タイマーを回し続ける必要があります。
    これらのレジスタを変更することで余分な処理が走り、割り込み周期が変わってしまいます。
    このことはMPLABのシミュレータで確認できます。
    ※以上は「ある程度正確な」1秒です。実際にはC言語による冗長な処理が入るため精密な1秒かどうかは判定しかねます。
    より、精密に処理するには、アセンブラで記述する必要があると思います。

    次に、main()関数のボタン入力判定です。

    while(1){                                       // 繰り返しループ
    if (!SWT_MODE) { // モードスイッチが押された
    PORTB = 0xFF; // 表示クリア
    __delay_ms(50); // 100ms待って(チャタリング防止)
    __delay_ms(50);
    if (!SWT_MODE) { // まだ押されてる
    if (slp_on == 2) { // スリープ中の場合、起きる
    slp_on = 1;



    SWT_MODEはdefineで定義したRA4ポートにつながっている押しボタンスイッチです。
    スイッチはプルアップ抵抗を介して接地しているので、押されているあいだ0になるので「!SWT_MODE」としています。
    チャタリング防止のため100ms待ち、まだボタンが押されているならばボタンに関する処理を行います。
    モードボタンは単独でポートを占有しているので良いのですが、今回の回路ではポートに余裕がないので、他の二つのスイッチはLED出力と兼用しています。

        if (dsp_mode > MODE_CLOCK) {       // 時刻モード以外
    TRIS_1 = 1; // スイッチ1のポートを入力にする
    __delay_us(10); // 10us待って
    if(!SWT_1) { // スイッチ1が押されてたら
    PORTB = 0xFF;
    __delay_ms(50);
    __delay_ms(50);
    if(!SWT_1) {
    if (slp_on == 2) {



    2行目の所でPORTAの2(TRIS_1)を入力に変え、スイッチの入力をチェックしています。
    スイッチ1はRB2に接続しているので、押すとLEDの一部が意味なく光りますが・・・
    ちなみに、今回のデジタル時計では6つのモードを設けています。

    #define MODE_CLOCK    0                          // 時計モード
    #define MODE_SECOND 1 // 秒表示モード
    #define MODE_WATCH 2 // ストップウオッチモード
    #define MODE_ADJHH 3 // 時・設定
    #define MODE_ADJMM 4 // 分・設定
    #define MODE_SLEEP 5 // スリープ設定

    このそれぞれのモード時で、スイッチ1とスイッチ2の役割を変えています。
    スイッチ1は主に数字の操作

        switch (dsp_mode) {
    case MODE_SECOND: // 秒モードの時
    t_save = 0; // 0リセット
    ss = 0;
    break;
    case MODE_ADJHH: // 時設定の時、
    hh++; // 時をカウントアップ
    break;
    case MODE_ADJMM: // 分設定の時、
    mm++; // 分をカウントアップ
    break;
    case MODE_WATCH: // ストップウオッチの時
    stp_watch = 0; // 0リセット
    break;
    }

    スイッチ2はン・オフ切り替え

        switch (dsp_mode) {
    case MODE_WATCH: // ストップウオッチの時
    wat_on = !wat_on; // スタート・ストップ切り替え
    break;
    case MODE_SLEEP: // スリープモードの時
    slp_disp++; // スリープ表示の切り替え
    if (slp_disp == 2) slp_on = 1;
    else slp_on = 0;
    if (slp_disp > 2) slp_disp = 1;
    break;
    }

    mainの最後では、各モードにより表示する数字の桁の操作をしています。

        switch (dsp_mode) {                            // 表示桁の抑制
    case MODE_SECOND: // 秒表示:下2桁のみ
    if (dg_f > 1)
    dg_f = 0;
    case MODE_ADJHH: // 時設定
    if (blink && dg_f > 1) // ブリンクオンで上2桁を抑制
    dg_f = 0; // 結果0か1



    解説は以上です。

    タグ:PIC 16F648A 7セグLED

    7セグLED時計の製作②

    2009.06.12

    今日はとりあえずPICCのソースリストを公開

    リストはこちら

    次回は内容を説明します

    タグ:PIC 16F648A 7セグLED

    ページ移動