PIC16F1619の基本動作から応用プログラムまでを学びます。

ホーム
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
    
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
モールス練習機
2020-11-20

アマチュア無線のCW モールス信号は、なかなか正確な符号を送信するのが難しいものです。自分で送っている信号を耳で聞くだけでは、どこがどう不正確なタイミングなのか客観的に評価することができません。そこで、PIC16F1619のSMTを利用してキーイング信号のパルス幅を測定し、測定結果はEUSARTからシリアルUSB変換器を経由してPCに送信します。PCの通信ソフトでこの信号を読むことで、短点と長点の長さや符号の間隔の比較など理解しやすくなります。自分の癖に驚くことでしょう。

PICのペリフェラルは以下の用途に使用しています。

電鍵
RC7に接続してCLC1を軽油しSMT1SIG入力でモニタしている。Keyを押すと出力が LOW になる負論理出力
TMR4
CLC1と共に機能し、電鍵信号のチャタリングを排除しきれいな信号を作るために使用します。 電鍵からの信号が変化すると、変化から20mS後にパルスを発生します。
CLC1
電鍵信号の変化から20mS後に発生するパルスで、電鍵信号をラッチします。信号変化から20mS立つとチャタリングもおさまり安定した信号が得られ、この信号を SMT に送ります。

SMT1
信号の継続時間測定に使用
Clockは、31.25kHzの 1/8 をカウントするので、256us単位です。SMTの動作モードを High and Low とし、チャタリングを排除した電鍵信号は。SMT1SIG に入力。PeriodeRegister によるロールオーバー周期は、2 ms として、この時間電鍵が押されないと送信文が終了したと判断します。
EUSART
SMTで測定した電鍵信号の On/Off を、mS 単位に変換した文字列をUSBシリアル変換モジュールに送信します。比較的高速の115200 baud で送信します。
TMR2
サイドトーン用の 800Hzを作るため PWM3と共に機能し、サイドトーンのベースとなります。Fosc/4 (8MHz)を 1/100 し、80kHz のPWM周期で、その5回に一度(16kHz)、波形データを更新します。
PWM3
波形データは、正弦波を20分割した値を使用するので、出力波形は、800Hz (16kHz/20)。PushSWを押すと、TMR2 postscaler が、1:5 -> 1:6 -> 1:4 -> 1:5 と変化するので、出力される周波数数も、666、800、1000Hzから選ぶことができます。

PCで受信

USBシリアル変換器とPCをUSBケーブルで接続し、CoolTermなどの通信ソフトを立ち上げます。
通信ソフトの設定画面で

に設定し接続を有効にします。

PICをリセットすると『Ready』表示され、信号待ちの状態になります。電鍵のキーを押すとサイドトーンが聞こえ、CoolTerm画面にパルス幅が表示されます。 PushSWを押すと、トーン周波数数を、666、800、1000Hzから選ぶことができます。PCのCoolTermでの受信例は下図の様に、モールス送信した信号のパルス幅がms単位の一覧形式で表示されます。mark が電鍵を押している時間、space が離れている時間です。2秒以上離れていると文章が終了したと判断して「 - - - 」を表示します。


プログラム

プログラムは、main.c, IOCNFG.h, IOCNFG.c から構成されています。
IOCNFGには、コンフィグレーションと周辺機器などの初期設定がまとめられ、プログラムの主要フローは、main.c に書かれています。main.c を下に示します。IOCNFG.h, IOCNFG.c は、ダウンロードして確認ください。

モールス練習機 B04_CW_pulse.X.zip

main.c

/*******************************************************
* CW_pulse
* SMT Hight-Low mode で、電鍵のOnOffパルス幅をms単位で
 * 測定し、EUSART経由しUSBに変換してPCに送信する
 *******************************************************/

#include "IOCNFG.h"

uint8_t wave[] = {    // Sin定数 20分割 MAX 99
     97,90,79,65,50,34,20,9,2,0,2,9,20,34,50,65,79,90,97,99
};

uint16_t Pdata;         // work data
uint8_t  num;           // Space配列ポインタ
uint8_t  p_wave;
uint8_t  data;

void main(void){
    IO_Init();              // SYSTEM_Initialize();                    // デバイス初期化
    INTCONbits.GIE = 1;     // 割り込みを有効にする
    INTCONbits.PEIE = 1;
    while (1)               // 繰り返し
    {
        num = 1;                                // 信号番号
        SMT1PWAIF = 0;                          // フラッグクリア
        SMT1PRAIF = 0;
        SMT1IF = 0;
        SMT1CON0bits.EN = 1;                    // SMT有効
        SMT1CON1bits.SMT1GO = 1;                // 測定開始
        printf("\r\nready 21\r\n");             // 準備完了メッセージ送信
        printf(" -  mark  space (ms)\r\n");     // タイトル送信
        // ---------- 赤外線信号を受信する -------------------------------
        while(!SMT1IF){             // Gapまで繰返
             // Side Tone の変更 _______________________________________
                if(!RC4){                       // SWが押されたら
                    LATA5 = 1;                  // LED を点灯
                    while(!RC4);                // SW が離れるのを待つ
                    LATA5 = 0;                  // LED を消灯
                    switch(T2CON){                      // トーン周波数変更
                        case 0x84: T2CON = 0x85; break; // 666Hz
                        case 0x85: T2CON = 0x83; break; // 1 kHz
                        default:   T2CON = 0x84; break; // 800Hz
                    }
                }
            // ------------------------
            if(SMT1PWAIF){                      // mark終了なら
                SMT1PWAIF = 0;                  // フラグクリア
                Pdata = SMT1CPW*32/125;
                printf("%2d %5d",num++,Pdata);  // mark時間
            }
            if(SMT1PRAIF){                      // space終了なら
                SMT1PRAIF = 0;                  // フラグクリア
                Pdata = SMT1CPR * 32 / 125;     //  msに変換し負数で保存
                printf(" %5d\r\n",Pdata);       // mark時間
            }
        }
        SMT1IF = 0;                             // フラグクリア
        printf("   ---\r\n");                   // Gap時間
        //------------ 受信結果を送信する ------------------------------
        SMT1CON1bits.SMT1GO = 0;                // 測定終了
        SMT1CON0bits.EN = 0;                    // SMT無効
    }
}

// ------------ 割り込み処理 ---------------
void __interrupt() INTERRUPT_InterruptManager (void){
    if(PIR1bits.TMR2IF == 1){       // TMR2割り込みなら
        PIR1bits.TMR2IF = 0;            // フラグクリア
        PWM3DCH = wave[p_wave];         // 波形定数を更新
        if(p_wave >= 19){               // 零点なら
            if(!RC7) p_wave = 0;        //  SW ON で継続
        }else{                          // 零点以外なら
            p_wave ++;                  //  波形定数を進める
        }
    }
}
/** End of File **/