【PICマイコン入門8】UARTの使い方と文字列の送受信 | アナデジ太郎の回路設計

【PICマイコン入門8】UARTの使い方と文字列の送受信

UART通信波形 ソフト設計

この記事でわかること

・PICマイコンのUART機能の使い方
・文字列の送受信プログラムの設計方法
・ロジックアナライザによるUART信号の測定

PICマイコンとPC間でシリアル通信を行うUART機能の使い方と、
送受信プログラムの設計方法や、ロジックアナライザで測定した信号波形についても解説します。

本記事で使用する新居浜高専PICマイコン学習キットについては下記記事で解説しています。

キットの回路図やプログラムはキットを販売している秋月電子のHPからダウンロードできます。
秋月電子 新居浜高専PICマイコン学習キットVer.3 ACアダプタ付

また、参考書も販売されています。

※本記事はPICマイコン学習方法の一例を紹介するものであり、
 ここで紹介するキットやソフトの動作を保証するものではありません。
 キット等の購入については自己責任でお願いします。
 (不明点等の質問にはお答えできません)

<本ソフトの利用環境と設定について>
本記事におけるMPLABの開発環境は以下の通りです。
・MPLAB X IDE v.15
・XC8 v2.46
・Device Family Pack PIC16F1xxxx_DFP(1.24.387)

※ダウンロードしたプロジェクトファイル(NNCTkit_v3.X)は、
 そのままビルドするとエラーになるため、以下の変更を実施しました。

・helpstr.h 9行目
 変更前:const __section(“title”) unsigned char title[224]={
 変更後:const __section(“help_title“) unsigned char help_title[224]={

セクション名がtitleだとエラーになるので、別の名前にします。
ここではhelp_titleにしましたが、何でも良いです。

この時、配列名はtitleのままでも問題ありませんが、
他のデータ同様、配列名をセクション名と同じにする場合は、
この配列を使用しているソースファイルの方も直します。

・monitor.c 2093行目
 変更前:TX1REG = title[i];
 変更後:TX1REG = help_title[i];

MPLABの使い方については下記で解説しています。

PICマイコンとPC間の通信環境

マイコンとPCとの通信は、UART(※1)(ユーアート)と呼ばれる
非同期式(※2)シリアル通信がよく利用されます。

※1:Universal Asynchronous Receiver Transmitter(汎用 非同期式 受信機 送信機)
※2:クロック信号を使用せず、お互いにタイミングとスピードを合わせて通信するため、調歩同期式とも呼ばれる。

UART通信

この通信方式は送信信号(TX)と受信信号(RX)の2つの信号線を使用し、
相手の送信信号を自分の受信信号に、自分の送信信号を相手の受信信号として接続します。

UART接続

UART信号は基本的には以下の形式となります。

UART信号形式

データが無い状態ではHレベル(1)で、
Lレベル(0)が来たら、スタートビットとして、データの始まりと判断します。

その後、8bitデータがLSB(最下位bit)から送信され、
その後にパリティビット(誤り訂正符号)が追加される場合があります。

パリティビットには、データを送信する際にHレベル(1)の数が常に偶数、
又は奇数になるようにH又はLレベルにするようにし、
前者を偶数パリティ、後者を奇数パリティと呼びます。
(本キットでは、パリティ無で行っています)

最後にHレベル(1)が来たらストップビットとして、データの終わりと判断します。

データの通信速度ですが、ボーレート(Baud Rate)と呼ばれ、
1秒間に送信するビット数(bps:bit per second)で表現します。

使用されるボーレートは、4800bpsや19200bps等がありますが、
本キットでは、一般的に最もよく使われる9600bpsを採用しています。

通信回路

UART接続回路

キットのUART通信回路は上図のようになっており、PICKit(※3)との接続回路と共用しています。

※3:PICマイコン用のデバッカであり、PICkitを経由してPCと接続し、プログラム開発ソフトMPLABを使用して、
  
PICへのプログラム書込みや、デバックを行います。PICkitについては、先程紹介したキットの解説記事で説明しています。

学習キットとの接続図
PICマイコン~PC間 USBシリアル通信構成
PICkit接続構成

UART通信を使ってPICマイコンとPC間でデータを送受信しますが、
PICからの通信信号は5V系(又は3.3V系)ロジック信号であるため、
PCに直接接続することができません。

PCのインターフェースについては、以前はD-Subコネクタ接続によるRS-232C通信でしたが、
現在はUSB通信が主流となっています。

このため、ロジック信号をUSB信号に変換するための回路が必要となり、
ここでは、USBシリアル変換モジュールを使用しています。

FT234X 超小型USBシリアル変換モジュール
(秋月電子の通販サイトから購入)

シリアルUSB変換モジュール

このモジュールに搭載されているFT234XDは、
USB関連では定番メーカーと言えるFTDI社製のUSBシリアル変換ICです。

USBシリアル変換モジュール回路図

ICの信号レベルは3.3Vですが、5Vトレラント仕様なので、
PICマイコンからの5V系論理信号を直接入力できます。

ちなみに、PICマイコンの論理入力はTTLレベル(2.0V/0.8V)なので、
モジュールからの3.3V系論理信号を認識することができます。

キットとモジュールの接続方法については、先程紹介したキットの解説記事で説明しています。

学習キットとUSB変換モジュールの接続状態

PCには、通信用ソフト(Tera Tarm:テラターム)をインストールして使います。

Tera Termの画面

Tera Tarm:外部機器とシリアル通信するためのソフトで、
     このような通信ソフトをターミナルソフトや、ターミナルエミュレータと呼びます。

    Tera Termの使い方については下記記事で解説しています。



PICマイコンのUART機能

PIC16F18857のUART通信は、EUSART(※4)と呼ばれる機能で行われます。

※4:Enhanced Universal Synchronous Asynchronous Receiver Transmitter
  
 (拡張 汎用 同期 非同期 受信機 送信機 )

UARTに対して、先頭にE、途中にSが付いた名称となっていますが、
Eは拡張機能(ボーレートの自動検出(※5)など)が加わり、
Sは同期式通信もできるという意味です。

※5:ASCIIコードの0x55(文字「U」)を受信することで、送信側のボーレートを検出して、自動的に設定する機能

但し、非同期通信が送信と受信が同時にできる全二重式であるのに対し、
同期通信は、2本の信号線のうち、1本をクロック信号(CK)、
もう1本を送受信データ信号(DT)に使うため、送信と受信を交互に行う半二重式となっています。

EUSARTの同期通信は、あまり利用されていないことから、
本記事では、非同期通信に限定して説明します。

非同期送信機

EUSART送信ブロック図

非同期送信機を有効にするには、以下の設定を行います。
・TX1STAレジスタの TXEN ビット = 1(送信有効)
・TX1STAレジスタの SYNC ビット = 0(非同期モード)
・RC1STA レジスタの SPEN ビット = 1(シリアルポート有効)

※TX1STA:送信ステータスおよび制御レジスタ
 RC1STA:受信ステータスおよび制御レジスタ

送信処理の流れを説明します。

TX1REG(送信データレジスタ)にデータを書き込むと、
自動的にTSR(送信シフトレジスタ)に転送されます。
(TSRはソフトから読書きできません)

そして、UART信号形式に従い、スタートビットの0をつけてから、
最下位ビット(LSB)から1ビットづつ、送信(TX)ピンにデータが出力されます。

最上位ビット(MSB)まで出力したら、最後にストップビットの1を出力して終了となります。

従って、データを送信するには、ソフトでTX1REGにデータを書き込めば、
後はマイコンが自動的にUART形式で送信してくれます。

データの送信方法

データを書込むタイミングですが、
TX1REGからTSRへのデータ転送は、TSRにデータが残っていると行われないので、
前回のデータ送信が終わり、TSRが空になるのを待つ必要があります。

TSRが空かどうかは、TX1STAレジスタの
TRMT(TSR状態)フラグが1であることで確認できます。

ソフトではWhile文等を用いて、定期的にTRMTの値をチェック(ポーリングと呼ぶ)して、
1になったらTX1REG1にデータを書き込むようにします。

TRMTの他にも、PIR3(ペリフェラル割込状態3)レジスタにある
TXIF(送信割込みフラグ)も利用できます。

TXIFはTXREG が空の時に1(送信割込み発生(※6))となるので、
このフラグが1になったらTX1REG1にデータを書き込む方法もあります。

※6:TXIFが1でも、PIE3(ペリフェラル割込許可3)レジスタの
   TXIE(送信割込み許可)を1にしないと送信割込みは実行されません。

TXIFについてはポーリングではなく、割込み処理を使った送信もできます。
割込みを使う際はTXIEを1にすることで、TXREGが空になり次第、送信割込みが実行されます。

送信割込みでは、TX1REGにデータを書き込む処理を定義しておくことで、
割込み発生時にデータが送信されます。

この時、割込み処理内で、TXIEを0(送信割込み不可)にする必要があります。
そうしないと、送信が終わっても送信割込みが発生し続けてしまい、
通常処理が実行できなくなるからです。

以上から、送信処理を行うにはポーリング方式の方が簡単ですが、処理時間がかかるため、
他の処理も行う時間を確保したい場合には、割込み方式を利用します。

この後紹介するキットの送信プログラムでは、TRMTを使ったポーリング方式を採用しています。

9bitデータの送信

TX1STA レジスタの TX9 ビットを1にセットすると、送信データが9bitになります。
9bit目のビットは、複数台通信用のアドレスビットとして利用できます。

※9bit目をパリティビットに使用することもできますが、
 PICマイコンにはハードウェアによるパリティチェック機能は無いので、ソフトウェアで行う必要があります。

複数台通信は、主にRS-485インターフェースで行われる方式で、
1台の親機(マスター)に複数の子機(スレーブ)を接続し、
子機に割り当てた宛先アドレス(※7)で区別して送受信します。

※7:メモリアドレスのことではなく、子機につけた任意の番号(1,2,3など)のこと

複数台UART通信

送信する際は、9bit目を1にして、データビット(8bit)にアドレスをセットして送信し、
2回目以降の送信では、9bit目を0にして、データビットに送信したいデータをセットします。

子機側でアドレス検出モードを有効にしておくと、
親機側からの送信データのうち、9bit目に1がセットされている場合のみ受信します。

子機は受け取ったアドレスが自分のアドレスと一致したら、
アドレス検出モードを解除するようにソフト設計することで、
それ以降に送信されてくるデータを受信することができます。

アドレス検出モードについては、この後の受信ブロックで説明します。

ボーレートの設定

ボーレート(通信速度)は、BRG(ボーレートジェネレータ)と呼ばれるタイマで設定します。

タイマでは、クロック信号を分周(Fosc/n)してからカウントし、
ボーレートレジスタ(SP1BRG)の値+1に達したら、TSRが1ビット分、データを送信します。

SP1BRGは上位8bitのSP1BRGHと、下位8bitのSP1BRGLから構成され、
BAUD1CON(ボーレート制御)レジスタのBRG16(16bitモード)ビットを1にすると16bit、
0にすると下位8bitだけを使用します。

分周比nは、先程のBRG16と、TX1STA(送信ステータスおよび制御)レジスタの
BRGH(高速ボレート)ビットとの組合せによって決まります。

BRGカウンタ分周設定

BRG16=0(8bitレジスタ)の場合
 BRGH=1(高速選択)なら、Fosc/16
 BRGH=0(低速選択)なら、Fosc/64

となり、同じレジスタ値なら、BRGH=1の方がボーレートが4倍早くなります。

BRG16=1(16bitレジスタ)の場合
 BRGH=1(高速選択)なら、Fosc/4
 BRGH=0(低速選択)なら、Fosc/16

こちらは16bitによりSP1BRGの値を大きくできる分、分周比nが小さくなっています。

ボーレートの計算式は以下になります。
 ボーレート(bps)=Fosc/[n×(SP1BRG+1)]

以上から、Fosc=32MHzの場合、ボーレートを9600pbsに設定する方法は4通りあります。
 ①BRG16=0、BRGH=0、SP1BRG=51で、 9615bps
 ②BRG16=0、BRGH=1、SP1BRG=207で、9615bps
 ③BRG16=1、BRGH=0、SP1BRG=207で、9615bps
 ④BRG16=1、BRGH=1、SP1BRG=832で、9604bps
本キットのソフトでは、最も精度が高い④で設定しています。

送信ピンの選択

送信(TX)信号は固定されておらず、どのピンに割り当てるかは、
PPS(ペリフェラル・ピン・セレクト)モジュールにある
RxyPPS(Rxy 出力ソース選択)レジスタで指定します。
(xはポートの先頭記号(A,B,Cなど)、yはポート番号(0~7)が入る)

PPS出力ピンの設定

PIC16F18857の場合、TX信号はポートBとCから選択でき、
本キットのソフトではRB6ピンに設定するため、
RB6PPSレジスタにTX信号を指定するコード0x10をセットします。
 RB6PPS = 0x10



非同期受信機

EUSART受信ブロック図

非同期受信機を有効にするには、以下の設定を行います。
・RC1STAレジスタの CREN ビット = 1(受信有効)
・TX1STAレジスタの SYNC ビット = 0(非同期モード)
・RC1STA レジスタの SPEN ビット = 1(シリアルポート有効)

受信処理の流れを説明します。

受信(RX)ピンにデータが入力されると、
ボーレート発生器(BRG)で設定されたタイミングで、
データを1ビットづつ、RSR(受信シフトレジスタ)にセットされます。

RSRにセットされたデータのうち、スタートビットやストップビットを除いた
8bit(又は9bit)のデータビットのみがFIFOメモリ(※8)に転送されます。

※8:First-In First-Out(先入れ先出し)の略で、最初に読み込んだデータから読み出す構成のメモリのこと。

FIFOメモリは2キャラクタ(8bit又は9bitデータ2個分)まで保管でき、
そのデータはFIFOから転送されて、受信レジスタ(RC1REG)で読み出すことができます。
(RSRやFIFOはソフトからは読書きできません)

FIFOに2個分のデータが保管された状態で3個目のデータが来たら、
オーバーランエラーが発生し、RC1STA レジスタの OERR ビットが1にセットされます。

この時、FIFO バッファ内に既にある2個のデータは読み取ることができますが、
エラーがクリアされるまで追加のデータは受信されません。

エラーをクリアするには、RC1STA レジスタの CREN ビットを0(受信機無効化)にするか、
SPEN ビットを0(シリアルポート無効化)にして、UART機能をリセットする必要があります。

また、データの最後に来る筈のストップビットが検出されなかった場合、
フレーミング エラーが発生し、 RC1STA レジスタの FERR ビットが1にセットされます。

フレーミング エラーになっても、追加のデータは受信でき、
ストップビットが検出されればエラーはクリアされます。

データの受信方法

データが受信され、RC1REGにデータが入ると、
PIR3(ペリフェラル割込状態3)レジスタのRCIF(受信割込みフラグ)が1になります。

あらかじめ、PIE3(ペリフェラル割込許可3)レジスタの
RCIE(受信割込み許可)を1にしておくことで、
RC1REGにデータが入り次第、受信割込みが実行されます。

受信割込みでは、RC1REGからデータを読み出す処理を定義しておくことで、
受信したら、データを読み出すことができます。

データを読み出して、RC1REGが空になれば、RCIFは0になるので、
次回データが受信されるまで、受信割込みは発生しません。

9bitデータの受信

RX1STA レジスタの RX9 ビットを1にすると、9bitデータが受信できます。

送信ブロックで説明した通り、追加した9bit目のデータは、
複数台通信時のアドレスビットや、パリティビットに利用できます。

9bit目のデータをアドレスビットとして使用する場合、
RC1STA レジスタの ADDEN(アドレス検出)ビットを1にして、アドレス検出モードにします。

アドレス検出モードにすると、
受信データのアドレスビットが1なら受信処理(RCIFが1になる) を行うので、
宛先アドレスが送られてきた時のみ受け取ります。

そして、受け取ったアドレスが自分のアドレスと一致したら、
アドレス検出モードを解除(ADDEN=0)して、それ以降に送られてくる送信データを受信し、
別アドレスを受信したら、アドレス検出モードに戻す(ADDEN=1)ようにソフト設計します。

また、子機から返信する際は、自分のアドレスをつけて送信するようにすれば、
親機は、どの子機からの通信なのか判別することができます。

受信ピンの選択

受信(RX)信号は初期設定でRC7ピンに割当られていますが、
PPS(ペリフェラル・ピン・セレクト)モジュールにある
xxxPPS(xxx 入力選択)レジスタで変更できます。
(xxxは入力信号の名称(INT、RXなど)が入る)

PPS入力ピンの設定

PIC16F18857の場合、RX信号はポートBとCから選択でき、
本キットのソフトではRB7ピンにするため、
RXPPSレジスタにRB7ピンを指定するコード0x0Fをセットしています。
 RXPPS = 0x0F



UART通信プログラムの設計方法

PICマイコンの初期設定

プログラムでは、PICマイコンの初期設定として、動作周波数の設定を行います。
(プログラムコードの詳細は、ソースファイル(nnct_kit_v3.c)を参照下さい

コンフィグレーション設定(※9)は以下の通りです。
 ※9:クロックなどの動作環境設定

#pragma config FEXTOSC = HS
 外部発振器モード選択:HS(水晶振動子 4MHz以上)

#pragma config RSTOSC = EXT4X
 発振器の動作モード:PLL(※10)の4逓倍回路を使用
  ※10:Phase Locked Loop(位相同期ループ):クロック周波数を増加させる回路

PIC16F18857ではPLLにより、外部からのクロック信号の周波数を4倍に増やすことができ、
本キットでは、8MHzの水晶振動子から32MHzのシステムクロック周波数Foscを生成してます。

コンフィグレーション設定については、下記記事で解説しています。

EUSART機能の設定

初期設定関数SetConfigで、EUSART関連レジスタの設定を行います。
ここでは、非同期モード、送受信データ8bit、ボーレート9600bpsに設定し、
RX信号をRB7ピン、TX信号をBR6ピンに指定しています。

初期設定関数

グローバル変数の定義

グローバル変数は関数の外で宣言した変数で、同じソースファイル内の関数で共用できますが、
プログラムの規模が大きくなり、ソースファイルを複数に分けた場合は、
extern宣言することで、別のソースファイルでも使うことができます。

本キットのプログラムは、LEDやブザー等を動作させる16種類のソフトが入っている
メイン・ソースファイル(nnct_kit_v3.c)と、PCと通信を行うためのソフトが入っている
通信プログラム用・ソースファイル(monitor.c)の2つのファイルから構成されているため、
nnct_kit_v3.cで宣言した変数をmonitor.cでも使えるようにextern宣言しています。

プログラムを複数のファイルに分ける方法については下記記事で解説しています。

グローバル変数の定義

受信割込み処理

データを受信したら発生する受信割込み処理で行う内容を定義しています。
その内容は、受信データをrcvdataにセットし、受信フラグrcvflgを1にすることです。

これによって、受信したらデータがrcvdataにセットされるので、
この後説明するUART通信プログラムではrcvflgが1になったら、
rcvdataから受信データを読み出すようにしています。

割込み処理関数

UART通信処理

本キットではモニタプログラムと呼ばれるUART通信を行うプログラムがあり、
PCから送信された入力コードに応じて、マイコンを動作させます。

このプログラムは複雑で規模が大きいため、
本記事では、その一部を簡略化して記載しています。

初めに、モニタプログラムの動作について簡単に説明します。

PCから、文字「H」から始まるコード(Hコマンド)を受信した場合、
ヘルプ画面(モニタプログラムの使用説明など)が表示されます。

同様に「P」,「L」,「G」,「E」コマンドが受信されると、
PICマイコンで動作させるプログラムのロード、リスト表示、実行、消去を行います。

上記のコマンド以外にも、ポートの入出力動作を行うコマンドがあります。
 例:RA1=1  RA1ピンをH出力する

また、これらのコマンドを使用してプログラムを作ることもできます。
その際は、行番号を先頭につけて入力します。
 例:01:RA1=1
   02:RB2=0
   03:RB3=1
    ・・・

入力したコマンドが間違っていたら、エラーメッセージが表示されます。

これらのコマンド入力をTeraTerm画面上で行うため、
モニタプログラムでは受信した文字をそのまま折り返し送信することで、
押したキーの文字が画面に表示されるようにしています。

送信する際は、TRMT(TSR状態)フラグが1(TSRが空)になるまで待機し、
送信シフトレジスタ(TSR)が空の時に送信データをセットするようにしており、
受信データが入ったrcvdataをそのまま、送信データレジスタ(TX1REG)に書き込むことで、
データが折り返し送信されます。

モニタプログラム1
モニタプログラム2

モニタプログラムでは、コマンドプロンプト表示や改行処理などを関数化しており、
その数は20種類以上あります。

ここでは、上記コード部分で使用している関数のみ記載します。



UART信号の波形測定

ここでは、先程説明したモニタプログラムにおいて、
文字「a」を入力してからEnterキーを押すと、無効なコマンドと判断され、
「Invaid Command!」と表示された時の送受信波形を測定してみました。

Tera TermによるPICマイコンとの通信

まずは、TeraTerm画面で「a」のキーを押すと、
ASCIIコードで文字「a」に該当する8bitデータ0x61 (0110 0001)を持つRX信号が受信されます。
(Enterキーを押さなくても、「a」のキーを押した時点でPCから送信される)

UART信号をオシロスコープで測定した波形

モニタプログラムは受信した文字を折り返し返信するので、
RX信号と同じ8bitデータ0x61を持つTX信号を送信します。

TeraTerm画面では送信データは表示されません。(※11)
 ※11:ローカルエコーを有効にした場合を除く

このため、「a」キーを押したことで「a」が画面表示されたように見えますが、
実は、マイコンから折り返し返信された「a」を表示しているのです。

このように受信したデータをそのまま折り返し送信する処理をエコーバックと言います。

波形を見ると、RX、TX信号ともにスタートビット(0)と、ストップビット(1)がついています。

ここで、RXとTX信号で電圧レベルが異なっているのは、
RX信号を出力するUSBシリアル変換モジュールが3.3V系で動作し、
TX信号を出力するPICマイコンが5V系で動作しているためです。

PICマイコンの論理入力はTTLレベル(2.0V/0.8V)なので、3.3V系のRX信号を認識でき、
USBシリアル変換モジュールは5Vトレラント仕様なので、5V系のTX信号を入力できます。

通信速度を見ると、スタートビットからストップビットまでの10bitで、
1.03msとなっており、1bitあたり103usかかっていることから、
ボーレートは、その逆数の約9600bpsであることがわかります。

この信号をロジックアナライザ(ロジアナ)を使って測定すると、
自動的にスタートビットとストップビットを認識し、
通信データの内容を16進数やASCIIコードで表示できるので便利です。

UART信号をロジックアナライザで測定した波形

ロジアナは台湾メーカーのZEROPLUS製LAP-C(16032)を使用しています。
比較的低価格ですが、電子工作で使うには十分な性能を持っており、
利用しているユーザーが多い製品です。

ロジックアナライザで測定する様子

次に、Enterキーを押してから、
「Invaid Command!」と表示されるまでの送受信信号です。

ロジアナ測定波形

Enterキーを押すと、CRコード(0x0D)(※12)が送信され、
それをマイコンがそのまま返信しているので、画面上でカーソルが行の先頭に復帰します。

 ※12:CR(キャリッジ・リターン):復帰(カーソルを左端の位置に戻す)を行う制御コード

CRコードを受信したマイコンは、入力されたコマンドに応じた処理を実行するのですが、
「a」は無効なコマンドなので、エラーメッセージ「Invaid Command!」を送信しています。

この時、メッセージの前後にCRとLFコード(0x0A)(※13)を送信することで、
PC画面上では改行してからメッセージを表示し、
更に改行してからコマンドプロンプト「>」を表示するようにしています。

 ※13:LF(ライン・フィールド):改行(カーソルを新しい行に移動)を行う制御コード
    CRとLFを組み合わせることで、カーソルが次行の左端に移動する。