実験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、 パリティ無し、 フロー制御無しに設定します。 |
/******************************************************************************* 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)? 1: 0; // データビット出力 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); } |
/******************************************************************************* 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); // デリミタの付加 } |
< 戻る >