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

ホーム
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
    
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
モールス発信器

モールス信号発信器は、マイコンなどからシリアル通信で文字を受け取り、その文字に対応するモールス信号を圧電スピーカーから発生させるものです。 受け取ったASCII文字は、プログラムメモリにあるm_Code一覧でモールス信号の断続音を表すmCodeに変換しています。

文字 モールス mCode
--- 長短点 --- 長さ
A ・- 1000 0000 0000 0010
B -・・・ 0111 0000 0000 0100
C -・-・ 0101 0000 0000 0100

<mCodeとは>
このプログラムのために開発したモールス信号固有のコードで、16bitで構成しています。 
16bitのうちの
  上位12bitが、長点[0]、短点[1の区別]を表し、
  下位 4bitが、符号の長さを表します。

プログラム

シリアルデータの受信は割込みで処理され、一時的にTempBufに保存されます。プログラムのメインループでは、TempBuf にデータが保存されているかを確認し、保存されていれば、RxBufにそのデータを移動した後に、一文字ずつ処理していきます。 まず、受信文字は、mCode変換ルーチンで英文小文字を英文大文字にしてから対応するmCodeに変換します。mCodeの左端のビットから順にモールス信号の短点、長点を処理しモールス音を発生さます。以下に、処理のフローチャートを示します。プログラムのソースリストと見比べてください。

<プログラム>

//--------------------------------------------------------------------
//  <モールス信号発信> 20130328 xM03_genStateSq リングバッファ
//  UART 9600bps で 通信文を受領 小文字は大文字に自動変換される。
//  通信速度は、短点 100mS固定となっているが、DotLen の 値を
//  変更することで、任意に設定できる。
//  PWMで 1KHz、duty 50%の方形波を出力する。
//
//  Notes:  4MhzM内部クロック
//          RB4        SW1入力(弱プルアップ)未使用
//          RB5        UART入力
//          RB6        SW2入力(弱プルアップ)連続Key
//          RC0        signalOut   ロジックレベル
//          RC1        signalOut 負ロジックレベル
//          RC5        AudioOut  P1A 音声出力
//  Language: MPLAB xc8   Target: PIC18F14K50
//--------------------------------------------------------------------
//  コメント修正
//--------------------------------------------------------
#include <xc.h>

//------------- 通信速度 ---------------------------------------------
// 時間間隔 mSec単位で指定する
#define  DotLen    100     // 短点の長さ
#define  BarLen    300     // 長点の長さ
#define  markSp    100     // マーク間の長さ
#define  charSp    300     // 文字間の長さ
#define  wordSp    700     // 単語間の長さ
//--------------------------------------------------------------------
#define maxBuf   80                 // シリアル受信バッファ数

#define portAudio TRISCbits.TRISC5
#define portRC0   LATCbits.LATC0
#define portRC1   LATCbits.LATC1
#define SW1       PORTBbits.RB4
#define SW2       PORTBbits.RB6
#define TimeUp    TMR0IF

//-------------- 制御ステート --------------------------------
#define  waitCommand    0
#define  markOut        1
#define  waitMarkEnd    2
#define  waitSpEnd      3
#define  waitNextChar   4

//-------------- コンフィグレーション --------------------------------
#pragma config MCLRE  = OFF
#pragma config PWRTEN = OFF, BOREN  = OFF, BORV   = 30
#pragma config WDTEN  = OFF, WDTPS  = 32768
#pragma config STVREN = ON
#pragma config FOSC   = IRC  //  内部クロック
#pragma config PLLEN  = ON,  CPUDIV = NOCLKDIV, USBDIV = OFF
#pragma config FCMEN  = OFF, IESO   = OFF, HFOFST = OFF
#pragma config LVP    = OFF, XINST  = OFF, BBSIZ  = OFF
#pragma config CP0    = OFF, CP1 = OFF, CPB = OFF, CPD = OFF
#pragma config WRT0   = OFF, WRT1 = OFF
#pragma config WRTB   = OFF, WRTC = OFF, WRTD = OFF
#pragma config EBTR0  = OFF, EBTR1 = OFF, EBTRB = OFF

//-------- プロトタイプ ----------------------------------------------
void delaySet(unsigned int);
void MarkOn(void);
void MarkOff(void);
unsigned int Ch_mCode(char);
char sChar(void);

// -------------- 共通変数 変数 --------------------------------------
char RxBuf[maxBuf];           // Rx受信バッファ
char ptrRx;                   // Rx書込みポインタ
char ptrIn;                   // Rx読込みポインタ
char state;                   // モールス発信ステート

//---------------- m_Code定数 ----------------------------------------
// 16bitの上位12bitが、長[0]、短[1]を表し、
//        下位 4bitが、符号の長さを表す。
// 並び順は、ASCIIコードと同じ
//--------------------------------------------------------------------
const unsigned int m_Code[] = {
         0,0x5006,0xB406,     0,     0,     0,     0,0x8406,  // !"#$%&'
    0x4805,0x4806,     0,0xA805,0x3006,0x7806,0xA806,0x6805,  //()*+,-./
    0x0005,0x8005,0xC005,0xE005,0xF005,0xF805,0x7805,0x3805,  //01234567
    0x1805,0x0805,0x1C06,     0,     0,0x7005,     0,0xCC06,  //89:;<=>?
    0x9406,0x8002,0x7004,0x5004,0x6003,0x8001,0xD004,0x2003,  //@ABCDEFG
    0xF004,0xC002,0x8004,0x4003,0xB004,0x0002,0x4002,0x0003,  //HIJKLMNO
    0x9004,0x2004,0xA003,0xE003,0x0001,0xC003,0xE004,0x8003,  //PQRSTUVW
    0x6004,0x4004,0x3004,     0,     0,     0,     0,     0,  //XYZ[\]^_
    };

//-----------------シリアルデータ文字取得---------------------------
// RxBufに文字がある場合は、その文字を返す
//              ない場合は、「0」を返す。
// 使用している共通変数   ptrIn  ptrRx  RxBuf[]
// 使用している定義       maxBuf
//--------------------------------------------------------------------
char gChar(void){
    char ch;
    RCIE = 0;                             // 受信割込み不許可
    if(ptrIn != ptrRx){                   // 受信データがあるなら
        ch = RxBuf[ptrIn];                //   戻り値のデータを取得
        if(++ptrIn >= maxBuf) ptrIn = 0;  //   ポインタを+1
    }else{                                // バッファが空なら
        ch = 0;                           //   戻り値を「0」にする
    }
    RCIE = 1;                             // 受信割込み許可
    return ch;
}

//-----------------低優先割込みの処理---------------------------------
// 低優先割込みはUARTに使用
//--------------------------------------------------------------------
void interrupt low_priority Lo_Isr(void){
    // -------------- UART からの受信 --------------------------------
    char RxData;
    char tpPtr;
    if(RCIF){
        RxData = RCREG;
        if(OERR){                             // Overrunエラーなら
            CREN=0;                           //  エラーをクリア
            CREN=1;                           //
        }else{                                // 通常受信なら
            tpPtr = ptrRx;                    // ポインタを保存
            if(++ptrRx >= maxBuf) ptrRx = 0;  // ポインタを+1
            if(ptrRx != ptrIn){               // バッファに空きがあるなら
                RxBuf[tpPtr] = RxData;        //   データを保存
            }else{                            // バッファフルなら
                ptrRx = tpPtr;                //   ポインタを戻し
            }                                 //   データを破棄
        }
    }    // UART RxIF}
}
//----------------------メインプログラム------------------------------
void main(void){
    unsigned int mCode;                // モールス発信用コード
    char mLength;                      // 該当コードのマーク数
    char mChar;                        // 送信する文字コード
    OSCCON = 0b01010010;               // 内部クロック4Mhz
    LATC   = 0b00000010;               // PortC  RC2,3,4,5出力
    TRISC  = 0b11000000;               // PortC  RC2,3,4,5出力
    ANSEL  = 0b00000000;               // デジタル
    ANSELH = 0b00000000;               // デジタル
    WPUB4 = 1;                         // RB4を弱プルアップ
    WPUB6 = 1;                         // RB6を弱プルアップ
    RABPU = 0;                         // 弱プルアップを有効化
// --------------- Timer0 の 設定 ------------------------------------
// システムクロック(4Mhe/4)をカウントする
// Timer0のPreSに16がセットされるので16uSecのカウント
// フルカウントで 1.1 Sec
// -------------------------------------------------------------------
    T0CON = 0b10000011;

// ----------- CCP PWM の 設定 (1KHz Duty 50% 方形波発生で使用)------
// システムクロック(4Mhe/4)をTimer2でカウントする。PSが1/4
// PR2に249がセットされるので1KHzの繰返しとなる。
// CCPおよびTimer2関連レジスタは以下のように設定される
//--------------------------------------------------------------------
    CCP1CON = 0b00001100;             // PWM_MODE_1、SINGLE_OUT
    PSTRCON = 0b00001111;             // PWM出力はP1A,B,C,Dピン
    CCPR1L  = 125;                    // PWMにDutyをセット
    T2CON   = 0b00000101;             // プリスケラ 1/4,ポストスケラ 1/1
    PR2     = 249;                    // プリセット値 249
    TMR2IE = 0;                       // 割込みOFF
    TMR2IP = 1;                       // 割込みを高優先に設定
    TMR2IF = 0;                       // 割込みフラッグをクリア
// ----------- UART 初期化 -----------
    RCSTA   = 0b10010000;             // UART送受信を有効
    TXSTA   = 0b00000100;             // 8Bit非同期受信のみ
    BAUDCON = 0b00001000;             // HI-16Bitボーレート
    SPBRGH  = 0;                      // 103
    SPBRG   = 103;                    // 9600ボー@4MHz
    RCIE = 1;                         // 受信割込み許可
    RCIP = 0;                         // 受信低優先割込

// ----------- 変数 初期化 -----------
    ptrRx = 0;                       // Rx暫定書込みポインタ
    ptrIn = 0;                       // Rx受信文字ポインタ
    state = waitCommand;             // モールス発信ステート

// ----------- 割込み初期化  -----------------------------
    IPEN=1;                           // 2段階の割込みに設定
    GIEH=1;                           // 高優先割込みを許可
    GIEL=1;                           // 低優先割込みを許可
// --------------- 開始の合図信号 ------------------------------------
    portAudio = 0;                    // AudioPortを出力に設定 (Mark)
    delaySet(DotLen);                 // 短点の長さをセット
    while(!TimeUp);
    portAudio = 1;                    // PortをHi-Impedance (Space)
// --------------- 繰返し動作 ----------------------------------------
    while(1){
    switch(state){
        case waitCommand:  // ---- 処理指示を待つ ---------------------
            if(SW2 == 0){                        // SW2 Pushで
                MarkOn();                        //  マークの開始
            }else{                               // 離すと
                MarkOff();                       //  マークの終了
            }
            mChar = gChar();                     // 一文字取得する
            if(mChar == 0) break;                // 空なら繰返し待つ
            mCode = Ch_mCode(mChar);             // 文字をmCodeに変換
            if(mCode){                           // 有効文字なら
                mLength = (char)(mCode & 0xF);   // mLengthを分離
                state = markOut;                 //   codeの処理をする
            }else{                               // スペースか無効文字なら
                delaySet(wordSp);                //   単語間 Space 送出
                state = waitNextChar;            //   次の文字を処理する
            }
            break;

        case markOut:     // ----- Markの処理 -------------------------------
            if(mCode & 0x8000){                  // Markを確認、短点なら
                delaySet(DotLen);                //   短点の長さをセット
            }else{                               // 長点なら
                delaySet(BarLen);                //   長点の長さをセット
            }
            MarkOn();
            mCode <<= 1;                         // 次のMarkの準備のため
            mLength--;                           //    mCodeをシフト
            state = waitMarkEnd;                 // Markの終了待ち
            break;

        case waitMarkEnd:  // ----- Markの終了を待つ ----------------------
            if(TimeUp){                          // Timer終了を待ち
                MarkOff();                       // MarkをOFFにし
                if(mLength){                     // code処理の途中なら
                    delaySet(markSp);            //   Mark間のSpaceセット
                    state = waitSpEnd;           //   次のMarkの処理
                }else{                           // code処理終了したなら
                    delaySet(charSp);            //   文字間の
                    state = waitNextChar;        //   次の文字の処理
                }
            }
            break;

        case waitSpEnd:    // ----- Mark間の終了を待つ ----------------------
            if(TimeUp) state = markOut;          // Timer終了を待ち
            break;                               //   次のmarkの処理

        case waitNextChar: // ----- 文字間の終了を待つ -----------------------
            if(TimeUp) state = waitCommand;      // Timer終了を待ち
            break;                               //   次の文字の処理

        default:           // ----- 予想外のstateなら ------------------------
            state = waitCommand;                 // コマンド待
            break;

        } // end Switch
    }     // end while
}         // end main

//------ モールス出力ポート制御 --------------------------------------
// Audio、ロジック出力のOn、Off
//--------------------------------------------------------------------
void MarkOn(void){
        portAudio = 0;                           // 音声 ON (Mark)
        portRC0   = 1;                           // 出力Hi (正論理)
        portRC1   = 0;                           // 出力Low(負論理)
}
void MarkOff(void){
        portAudio = 1;                           // 音声OFF(Space)
        portRC0   = 0;                           // 出力Low(正論理)
        portRC1   = 1;                           // 出力Hi (負論理)
}

//-------- ASCII文字を mCodeに変換 -----------------------------------
// 小文字は大文字に変換してから、m_code 一覧表を参照
// BS CRは、特殊文字として別途変換し、mCodeを戻り値とする
// 戻り値0 は、非該当文字またはスペース
//--------------------------------------------------------------------
unsigned int Ch_mCode(char ch){
    if(ch==0x08) return 0xFF08;                  // BS は、訂正符号
    if(ch==0x0D) return 0xAC06;                  // CR は、段落符号
    if((ch>=0x20) && (ch<0x60))                  // 数字および英文字は
          return m_Code[ch - 0x20];              //     一覧表で変換
    if((ch>=0x60) && (ch<0x7B))                  // 英小文字は大文字にし
          return m_Code[ch - 0x40];              //     一覧表で変換
    return 0;                                    // 対象外は「0」
}

// --------------- delaySet --------------------
// mS単位の遅延を行う
// Timer0の1カウント16uSecでフルカウントまでの時間が、
// 指定時間になるよう計算し設定している
// TimeUp(TMR0IF)は、メインのルーチン内でモニタしている
// ---------------------------------------------
void delaySet(unsigned int num){
    num = 0x10000 - (long)num * 1000 / 16;       // 設定カウントを計算
    TMR0H = num >> 8;                            // Timer 0 にセット
    TMR0L = num & 0xFF;                          // Timer 0 にセット
    TimeUp = 0;                                  // Timer 0 のフラグをクリア
}