シリアル通信USART【STM32のUSART詳細】
シリアルUSART通信は将来IoTにも応用できるペリフェラルなのでできるだけ早期に習得してもらいたいものです。
USARTはペリフェラルとしては機能の設定は比較的単純なのですが、文字列を扱うもののため使いこなすにはC言語のプログラミングのチカラが必要です。1文字の受信から文字列送受信のDMA転送までステップ毎に解説しています。
このサイトで紹介しているシリアルモニターを早めに導入(モニターデバッグを参照)してC言語プログラミングのスキルをあげるにも役立ててください。
USARTとは
UART(Universal Asynchronous Receiver Transmitter)シリアル通信は古くから使われている非同期の通信方式です。USART(Universal Synchronous & Asynchronous Receiver Transmitter)は非同期通信のUARTだけでなく、同期通信も可能とした方式です。
この章では同期・非同期シリアル通信USARTのうち非同期通信(UART)の解説をしていきます。USARTは同期通信にも対応していますがここでは取り扱いません。非同期方式は調歩同期式とも呼ばれ一般的な方式なのですが同期クロックを必要としないために、相手との通信速度がしっかり合っている必要があります。
そのため、システムクロックで解説したようにペリフェラルUSARTの供給クロック、つまりマイコンの動作クロックの周波数が安定していることが必要不可欠です
ペリフェラルにUSART通信を使用するアプリケーションではマイコンの動作クロックは安定した外部クロックを供給できる水晶振動子やセラミック振動子を使用することをおすすめします。
(STM32マイコンでは全二重および半二重通信に対応しています。)
調歩同期式でデータを送信する場合のフォーマットを見てみましょう。
通信データ(0か1のデジタル値)は開始ビット(スタートビット)と終了ビット(ストップビット)で囲んだブロックで送受信します。ブロック最初のビットをスタートビットといい、1から0に変化することで判明します。ブロック最後のビットを送信した後に1に戻しておきます。これをストップビットといいます。
調歩同期式ではスタートビットで送信側と受信側のタイミングを合わせて通信を行います。通信データの信頼性をあげるために使われるのがパリティビットでパリティビットを使用する場合のデータ長は9ビットになります。設定するパラメータは通信する相手と同じ仕様にする必要があります。
USART通信の初期化手順
USART通信の初期設定を実際のプログラムで解説していきます。
目的:設定する条件は以下のとおりです。
目的:使用するUSARTはUSART3でGPIOはPC10とPC11
■ ハードウェアフロー制御なし・パリティを使用しない
■ 通信速度(ボーレート)は9600
■ ストップビットは1
■ 送受信データビット長は8
① USART3にクロック供給
使用するUSART3にクロックを供給します。APB1バスに接続していますのでAPB1に供給します。
② GPIO設定1(PC10をUSART3_TXに設定)
USART通信の送信Txはオルタネート出力です。スピードはボーレートに合わせます。
③ GPIO設定2(PC11をUSART3_RXに設定)
USART通信の受信Rxはフローティング入力です。
④ USART3の初期設定
USART通信の初期設定を実行します。初期化はUSART_Init関数を実行して上記のパラメータを設定します。
USART初期化関数実行例: USART_Init(USART3, &USART_InitStructure);
関数の第1引数は設定対象のUSART(USART1-5:マイコンによります)を指定し、第2引数は構造体メンバになっていて以下に示します。
USART_BaudRateメンバでは通信速度を指定します。
USART_WordLengthメンバでは通信データのビット長を指定します。
USART_StopBitsメンバはストップビットの指定をします。この例では1ビットを指定しています。
USART_Parityメンバはストップビットの指定をします。この例では使用しません。
USART_HardwareFlowControlメンバはハードウェアフロー制御の設定をします。この例では使用しないのでUSART_HardwareFlowControl_Noneを指定します。
USART_Modeメンバは対象のUSARTで有効にする機能を指定します。通常はRx,Tx共に機能させる指定をします。
⑤ USART3を有効化する
これまででUSART通信の初期化ができましたので、USART_Cmd関数を実行して有効化します。
USART通信有効化関数実行例: USART_Cmd(USART3, ENABLE);
関数の第1引数には設定対象のUSART(USART1-5:マイコンによります)を指定し、第2引数はENABLEで有効、DISABLEで無効となります。
USARTを使った通信
初期化を終えると、アプリケーションプログラム内でデータの送受信ができるようになります。受信の場合はポーリングを使用して定期的に受信をチェックするか受信割り込みが発生した時にのみ受信処理を行うことをします。
データ受信(1文字)
通信において相手側が送信するタイミングに合わせて受信できればよいのですが、相手がいつ送信するかはわかりません。そこで定期的に受信があったかどうかを監視し、受信があったときにだけ受信処理をおこなうポーリング方式について解説します。
USART回路では受信があると受信レジスタにデータが一時保持されます。アプリケーションプログラム内で定期的に受信レジスタにデータがあるかどうかはUSART_GetFlagStatus関数で確認できます。この関数では受信に限らずUSARTのいろいろな状態をフラグで確認できます。ここでは受信データ通知フラグUSART_FLAG_RXNEがSET(1)であるとき受信データが受信レジスタにあることが確認できます。
ポーリングにより受信レジスタに受信データがあることが判明したあとはUSART_ReciveData関数を実行して受信データを1文字分取得します。この関数は戻り値として16ビットで定義されたものですが、受信データは8ビットです。
USART1文字受信関数実行例: RxData=(int8_t)USART_ReceiveData(USART3);
関数プロトタイプ:uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
関数の引数には設定対象のUSART(USART1-5:マイコンによります)を指定します。
データ送信(1文字)
送信は任意のタイミングで行うことができます。USARTの送信レジスタに1文字分ずつデータを書き込むと自動的に送信されます。連続してデータを送信する場合は前のデータが確実に送信されたことを確認してから次のデータを送信します。この確認にもUSART_GetFlagStatus関数を利用して送信が完了してレジスタが空になったことを確認できます。
送信が準備できた段階でUSART_SendData関数を実行して送信データを1文字分送信します。
USART1文字送信関数実行例: USART_SendData(USART3,'a');//1文字'a'を送信
関数の第1引数には設定対象のUSART(USART1-5:マイコンによります)を指定し、第2引数は送信する1文字を指定します。
転送したデータはマイコン側から例えばPC側にシリアルケーブルを介して転送するとシリアル通信のできるターミナルソフトで内容を確認できます。ターミナルソフトとマイコン側でシリアル通信の仕様を一致させると送受信ができるようになります。
表示に文字化けなどが起こる場合は転送速度が一致していないなどが原因です。マイコンの動作クロック周波数が不安定な場合も通信に不具合が起こる可能性も考えられますで、UART通信のような非同期(調歩同期)式の場合は安定した外部クロックを使うことが前提です。
送受信割り込み
前回はポーリングによる受信を行いました。ここでは受信があったときだけ処理を行う割り込みによる受信処理と送信したいときだけ割り込みを有効にして送信処理する方式をみていきます。割り込みを以外の設定はポーリング方式と同じなので省略しています。
目的:使用するUSARTはUSART3でGPIOはPC10とPC11
■ USART3の送受信割り込みの設定
① 割り込み初期化
割り込み初期化関数NVICで使用する割り込みの優先順位などを設定します。標準的な設定方法でUSART3の割り込みなのでNVIC_IRQChannelはUSART3_IRQnを指定します。
NVIC_IRQChannelCmdにENBLEに指定してIRQチャネルを有効にします。
② 割り込み有効化
受信割り込みで次の割り込みに対応するためにはステータスフラグをクリアしてからUSART_ITConfig関数で割り込みを有効にします。クリアにするにはUSART_ClearITPendingBit関数を使用します。
③ USART3有効化
USART3を有効化するといつでも割り込みによる受信を開始します。
④ アプリケーション部で送信関数実行
送信は専用に作成した送信関数USART_SendChar()を実行します。
⑤ 送信関数
送信するデータを関数に渡してから送信割り込みを有効にします。送信レジスタが空であると割り込みが発生し、USART3割り込みハンドラUSART3_IRQHandlerが呼び出されます⑥。
⑥ 送受信割り込みハンドラ
そこで、割り込みの原因である送信部の処理がされて文字が送信されることになります。
送信割り込みの場合は送信データをレジスタに書き込まれると割り込みフラグは自動でリセットされます。送信後は割り込みを停止しておきます。
割り込みを使用しているので送信関数USART_SendCharを実行すると送信レジスタが空になるまで無駄に待たせる必要はなく自動的に処理がなされるのでCPUの効率がよくなります。
この例では1文字だけを渡しているのですが、文字列として多数の文字を渡すと、割り込みによる送信の効果がより発揮されます。
文字列の送受信応用
これまでは送受信ともに1文字だけを扱ってきました。実用的な送受信通信を行うための方式にステップごと発展させていきましょう。
1文字の送受信では8ビットの変数1つを扱いましたが、文字列では配列かポインタの概念を使用します。文字列の取り扱いはマイコンの知識よりむしろC言語の文字列を扱う知識が必要です。このサイトではC言語の解説は行いませんが文字列、ポインタ、配列、アドレスあたりはしっかり理解しておいてください。
通信などのアプリケーションでは特に文字列をある程度自由自在に取り扱えるスキルが必要となってきます。基礎を十分理解して文字列を取り扱う関数など自分で作成できるようになるとアプリケーションの用途が広がります。
文字列の送受信を行う例を見てみましょう。ここでは割り込みを使用しないポーリング方式での文字列送受信を行っています。文字列の受信、送信でそれぞれ関数を作成しています。
マイコンのシリアル通信での送受信は1文字単位で行いますので、文字列は配列か、ポインタ変数など利用して一旦メモリに格納してから順次送受信する手順になります。
このメモリの格納場所をここでは送信バッファ、受信バッファと呼んでいます。
① 送受信に必要なペリフェラルの初期化
ペリフェラルの初期化はこれまでのとおりですのでここでは省略します。
② アプリケーション部で送受信関数実行
文字列の送受信はアプリケーション内に記述します。
ここではmain関数内の無限ループ内でPCのキーボードなどから入力された文字列データが登録している文字列と一致するかを判別するアプリです。
文字列を受信したことは常に受信フラグUSART_FLAG_RXNEで無限ループ内で監視しており、変化があると受信および文字列処理を開始します。
これは常時監視しているポーリング方式と呼ばれるものでCPUが働きっぱなしです。受信があったときだけ機能させCPUの負担を減らすには受信割り込み方式を採用します。
③ USART3受信関数
USART3_Rcv_string()は文字列を受信する関数です。
ここではキーボード等で文字列を入力し、キャリッジ・リターン(CR)までの入力文字ブロックを文字列として1文字ずつ順次受信バッファRxBufferに格納しています。
④ USART3送信関数
USART3_Send_string()は文字列を送信する関数です。
ここでは送信バッファTxBufferに登録格納された文字列をNull文字に到達するまで1文字ずつ順次送信します。割り込みを使用していないために、1文字送るたびに送信バッファが空になるまでフラグUSART_FLAG_TXE状態を確認待機する必要があります。
この例ではあるコードに文字列”ABC”を登録しておき、例えばPCとマイコン間のシリアル通信で、PC側からコードを送信したとき、マイコン側で登録コードと一致したときと、不一致のときの処理をしているものです。マイコンをその他PCなどから通信でリモート操作するときの基本的な考えに利用できます。C言語の配列やポインタに慣れるのにちょうどよいレベルのものですので、いろいろ条件を変更して試してみてください。
シリアル通信でもADコンバータのときと同様にDMAを使用すればより効率をあげることができます。つまり、CPUに頼らず文字列の送受信においてデータをメモリに自動転送できますので消費電力も抑えることができます。DMA転送は文字列コードが長くなればなるほど有用です。詳細はDMA(Direct Memory Access)【STM32のDMA詳細】で解説します。