実験2: ソフトウェア・シリアル通信

最近、HI-TECH PIC C Pro (v9.81 Lite mode)を使い始めました。添付されている、シリアル通信のサンプルソフト
を参考にして、いろいろ弄ってみましたが、どうもうまくいきません。ボーレートのタイミングが合わないのでしょうか。

参考になるサイトが無いかと探してみましたが、なかなか見つかりませんでした。
それでも、同じような実験をされている方のサイトが有りました。

PICで有名な 後閑哲也 先生のホームページでは、「8ピンPICマイコンの使い方がよくわかる本」の紹介があり、
サンプルソフトのダウンロードが可能で、その中に、TMR2を用いたソフトウエア通信のプログラムが有りました。
とても参考になりました。

また、シリアル通信で有名なエアーバリアブルさんのホームページBBSでも自分と同じような実験をされている方が
いて、同様に苦心されているようです。

HI-TECH のサンプルソフトを弄っていてもなかなか先に進めそうもないので、後閑先生のソフトを参考に
@TMR2を用いたもの、 Aインラインアセンブラを用い、タイミング調整をしたもの、 2種類のソフトを
制作してみました。どちらもうまく動いているようです。

マイコンは、 PIC12F683 を内蔵の8MHzのクロックで使用しています。周波数が同じであれば、他のPICでも使用
可能と思います。 皆様の追試を望んでおります。


使用方法
1) @またはAのモジュールとヘッダーファイルを組み込んでください。

2) mainのモジュールに必要な大きさのバッファを送信・受信用に確保してください。
  尚、送信あるいは受信しか使わない場合、送信・受信供用とする場合は、
  バッファは、1つでも構いません。

  例)
     char tbuff[31];  // \0を含めて31文字の送信バッファを確保する場合

3) ライブラリを使う前に、rs232_ini(); を実行して、初期化してください。
  また、通信中は、他の割り込み処理を停止してください。

3) 送信の場合は、バッファに文字列を格納してから、rs_puts(tbuff); を実行してください。
  送信されるデータには、自動的にCRLFが付加されます。

4) 受信の場合は、rs_gets(rbuff); を実行してください。CRLFをデリミタとして、
  rbuffに受信データが格納されます。尚、受信データの後ろには、CRLFを除いて、\0を
  付加しています。

5) 受信処理では、スタートビットおよびストップビットのタイミングエラーを検出できるように
  しています。エラーが有った場合には、rbuff に"ERR"が格納されます。

6) 通信の設定は、ボーレート9600bps、 データ長8ビット、 スタートビット、ストップビット共に1、
  パリティ無し、 フロー制御無しに設定します。
 



@Timer2 使用版
/*******************************************************************************

   RS232C送受信ライブラリ ヘッダファイル (rs232c.h)

*******************************************************************************/

#include <htc.h>

/***** ハード設定 ****/
#define BAUD        51      // 9600bps Fosc = 8MHz
#define DTIME       10      // 検出遅延時間
#define TXPIN       GP5
#define RXPIN       GP4

/**** 関数プロトタイプ宣言 ****/
void Send(char code);
char Receive(void);
void rs232_ini(void);
void rs_gets(char *buff);
void rs_puts(char *buff);

/*******************************************************************************

    RS232C送受信ライブラリ (rs232c.c) Timer2 使用

*******************************************************************************/


#include "rs232.h"

static volatile char dat;
static volatile char bCnt;
static volatile char bPos;

/* RS232C 初期化 */
void rs232_ini(void)
{
    T2CON  = 0x01;                  // 1/4プリ,1/1ポスト
    TMR2IF = 0;                     // 割り込みフラグクリア
    TXPIN = 1;
}

/* 1バイト送信サブ関数 */
void Send(unsigned char code)
{
    dat = code;                 // 送信データセット
    bCnt = 0;                   // ビットカウンタリセット
    bPos = 0x01;                // ビット位置リセット
    PR2 = BAUD;                 // ボーレート設定
    TXPIN = 0;                  // スタートビット出力
    TMR2 = 0;                   // タイマ2リセット
    T2CON = 0x05;               // 1/4プリ,1/1ポスト
    while(bCnt < 10){           // 送信完了待ち
        while(!TMR2IF)          // TMR2フラグ検出待ち
            ;
        TMR2IF = 0;
        bCnt++;
        if(bCnt > 0 && bCnt < 9){           // 1〜8bit
            TXPIN = (dat & bPos)? 10;     // データビット出力
            bPos <<= 1;                     // ビットシフト
        }
        if(bCnt == 9)                       // データ終了
            TXPIN = 1;                      // ストップビット出力
        if(bCnt == 10){                     // ストップビット終了
            T2CON = 0x01;                   // タイマ2停止
        }
    }
}

/* 1バイト受信サブ関数 */
unsigned char Receive(void)
{
    // GP0 = ~GP0;      // デバッグ
    while(RXPIN)                // スタートビット待ち
        ;
    bCnt = 0;                   // ビットカウンタ初期化
    dat = 0;                    // 受信データクリア
    bPos = 0x01;                // ビット位置初期化
    TMR2 = 0;                   // タイマ2初期化
    PR2 = DTIME;                // 1/2ビット幅に設定
    TMR2IF = 0;
    T2CON = 0x05;               // 1/4プリ,1/1ポスト、開始 
    while(bCnt < 10){           // 受信完了待ち
        while(!TMR2IF)
            ;
        TMR2IF = 0;
        switch(bCnt){
            case 0:                         // スタートビットの処理
                if(RXPIN) bCnt = 0xFF;
                else{
                    PR2 = BAUD;
                    bCnt++;
                }
                break;
            case 9:                         // ストップビットの処理
                if(RXPIN) bCnt++;
                else bCnt = 0xFF;
                T2CON = 0x01;               // TMR2停止
                break;
            default:                        // 1〜8bit目のデータ部の処理
                if(RXPIN) dat |= bPos;
                bPos <<= 1;
                bCnt++;
        }
        // GP1 = ~GP1;      // デバッグ
    }
    if(bCnt == 10)
        return(dat);            // 正常データを返す
    else
        return(0xFF);           // エラーフラグを返す
}

/* 文字列の受信 */
void rs_gets(char *buff)
{
    char *p, chr;
    
    p = buff;
    while(1){
        chr = Receive();
        if(chr == 0xFF){
            buff[0] = 'E';
            buff[1] = 'R';
            buff[2] = 'R';
            buff[3] = 0x00;
            break;
        }
        if(chr != 0x0d && chr != 0x0a)
            *p++ = chr;
        if(chr == 0x0d
            *p = 0x00;
        if(chr == 0x0a){ 
            *p = 0x00
            break;
        }
    }
}

/* 文字列の送信 */
void rs_puts(char *buff)
{
    while(*buff) 
        Send(*buff++);
    Send(0x0d);
    Send(0x0a);
}



Aインラインアセンブラ使用版
/*******************************************************************************

   RS232C送受信ライブラリ ヘッダファイル (rs232c.h)

*******************************************************************************/

#include <htc.h>
#include <string.h>

// 9600bps Fosc = 8MHz ウェイト定数
#define WC      66

// Pin の設定
#define TXPIN   _GPIO, 5
#define RXPIN   _GPIO, 4

// Status の設定
#define CARRY   _STATUS, 0
#define BANK01  _STATUS, 5

/**** 関数プロトタイプ宣言 ****/
void Send(char code);
char Receive(void);
void rs232_ini(void);
void rs_gets(char *buff);
void rs_puts(char *buff);

/*******************************************************************************

    RS232C送受信ライブラリ (rs232c.c) インラインアセンブラ使用

*******************************************************************************/

#include "rs232.h"

static volatile char wait;      // ウェイト設定用
static volatile char lpn;       // ループ変数
static volatile char iodat;     // 入出力データ

/* RS232C 初期化 */
void rs232_ini(void)
{
    #asm                        // GP5 = 1; 相当の処理
        bcf     BANK01          // bank0指定
        bsf     TXPIN           // TXPINをH
    #endasm
}

/* 1バイト送信サブ関数 */
void Send(char code)
{
    iodat = code;               // 引数を保存
    #asm
        bcf     BANK01          // bank0指定
        bcf     TXPIN           // スタートビット(L)出力
    ;
        movlw   WC              // 所定の時間待ち
        movwf   _wait           // *
        decfsz  _wait, f        // *
        goto    $ - 1           // *
    ;
        movlw   8               // ループ回数設定(8回)
        movwf   _lpn
    ;
    SENDLOOP    
        goto    $ + 1           // 遅延時間微調整
        rrf     _iodat, f       // 右側ローテート
    ;
        btfss   CARRY           // ビットのH/L検出
        goto    $ + 4           // CY = 0の時
        nop                     // 遅延時間微調整
        bsf     TXPIN           // TXPINをH
        goto    $ + 4           // CY = 1の時
        bcf     TXPIN           // TXPINをL
        nop                     // 遅延時間微調整
        nop                     // 遅延時間微調整
    ;
        movlw   WC - 1          // 所定の時間待ち
        movwf   _wait           // *
        decfsz  _wait, f        // *
        goto    $ - 1           // *
    ;
        decfsz  _lpn, f         // ループ終了確認
        goto    SENDLOOP
    ;
        goto    $ + 1           // 遅延時間微調整
        goto    $ + 1           // 遅延時間微調整
        goto    $ + 1           // 遅延時間微調整
        nop                     // 遅延時間微調整
    ;
        bsf     TXPIN           // ストップビット(H)出力
    ;
        movlw   WC              // 所定の時間待ち
        movwf   _wait           // *
        decfsz  _wait, f        // *
        goto    $ - 1           // *
    #endasm
}

/* 1バイト受信サブ関数 */
char Receive(void)
{
    //GP1 = ~GP1;       // デバッグ
    #asm
        bcf     BANK01          // bank0指定
        clrf    _iodat          // バッファクリア
        btfsc   RXPIN           // スタートビット(L)検出待ち
        goto    $ - 1
    ;
        movlw   WC / 2          // 所定の時間待ち
        movwf   _wait           // *
        decfsz  _wait, f        // *
        goto    $ - 1           // *
    ;
        btfsc   RXPIN           // スタートビットエラー検出
        goto    ERR             // エラー処理へジャンプ
        goto    $ + 1           // 遅延時間微調整
        goto    $ + 1           // 遅延時間微調整
    ;
        movlw   8               // ループ回数設定(8回)
        movwf   _lpn

    RECLOOP                     // データ取得ループ
        movlw   WC              // 所定の時間待ち
        movwf   _wait           // *
        decfsz  _wait, f        // *
        goto    $ - 1           // *
    ;   
        bsf     CARRY           // キャリーフラグセット
        btfss   RXPIN           // RXPIN H/L チェック
        goto    $ + 2           // RXPIN L の時
        goto    $ + 2           // PXPIN H の時
        bcf     CARRY           // キャリーフラグリセット
        rrf     _iodat, f       // 右側ローテート
    ;   
        decfsz  _lpn, f         // ループ終了確認
        goto    RECLOOP
    ;   
        movlw   WC              // 所定の時間待ち
        movwf   _wait           // *
        decfsz  _wait, f        // *
        goto    $ - 1           // *
    ;   
        goto    $ + 1           // 遅延時間微調整
        btfsc   RXPIN           // ストップビット検出
        goto    $ + 3           // 正常終了
    ERR                         // エラー処理
        movlw   0ffh            // エラーコード 0xff
        movwf   _iodat          // エラーコード保存
    #endasm
    return iodat;
}

/* 文字列の受信 (デリミタCRLFが必要) */
void rs_gets(char *buff)
{
    char *p, chr;
    
    p = buff;                           // 受信バッファのポインタをコピー
    do{
        chr = Receive();                // 1バイト受信
        switch(chr){
            case 0xff:                  // エラー検出時
                strcpy(buff, "ERR");    // バッファにエラーメッセージコピー
                break;
            case 0x0d:                  // デリミタの処理
            case 0x0a:
                *p = 0;
                break;
            default:                    // 通常のデータ処理
                *p++ = chr;
        }
    }while(chr != 0x0a && chr != 0xff); 
    //GP1 = 1;      // デバッグ
}

/* 文字列の送信 (CRLFを付加) */
void rs_puts(char *buff)
{
    while(*buff)            // buffの\0 までを送信
        Send(*buff++);
    Send(0x0d);             // デリミタの付加
    Send(0x0a);             // デリミタの付加
}



< 戻る >

inserted by FC2 system