LECTURE 3 USART によるシリアル通信

○ はじめに

ATMega8535 は、USART (Universal Synchronous and Asynchronous Receiver and Transmitter) と呼ばれる、シリアル通信を行うために必要な機能を備えています。この機能を使うと PC 等とシリアルポート経由でデータ通信を行うことができます。ここでは実際に、PC のシリアルポート (D-SUB 9ピン) と接続してデータ通信を行います。

○ USART について

USART とは Universal Synchronous and Asynchronous Receiver and Transmitter の略で、シリアル信号とパラレル信号間の変換を行うための集積回路のことを表す様です(Wikipedia によると)。ATmega8535 の USART の主な仕様は以下の様になります。

  • 全二重動作(送信と受信を同時に行うことができる)
  • 同期、非同期動作
  • 5/6/7/8/9 ビットデータの送受信
  • ストップビットは 1/2 ビットの両方をサポート
  • 奇数/偶数パリティビットの生成および検査が可能
  • データオーバラン(到着データを読む前に新しいデータが到着してしまい、未読データを失った)検出可能
  • フレーミングエラー(ストップビット検出失敗)検出可能
  • 受信完了/送信完了/送信データレジスタ空き を通知する割り込みをサポート

ATmega8535 では RXD ピン(PDIP パッケージでは 14ピン)をデータ受信に、TXD ピン(PDIP パッケージでは 15ピン)をデータ送信に使用します。理屈としては、この二つのピンをそれぞれ PC のシリアルポートの TXD/RXD に接続すれば良いわけです。

しかし、PC でサポートしている RS-232C(RS-232C は 25ピンの規格の昔の呼称であり、正式規格は 25ピンが EIA-232... で 9ピンが EIA-574... という名称らしいです)の信号レベルが -15V から 15V 程度であるのに対し、ATmega8535 の様なマイコンの信号レベルは 0 - 5V とずれています。そのため実際には、ATmega8535 と PC のシリアルポートの間に電圧変換用の IC(もしくはトランジスタ等で自作した回路)を入れる必要があります。本実験回路では、ADM3202 という RS-232ライン・ドライバ/レシーバを使用しています。秋月電子 で 200円くらいだった…かな?

↓赤枠内が ADM3202 です。
ADM3202

○ 関連レジスタ

USART 関連のレジスタを以下に紹介します。マクロについては、avr-libc で使用できる定義名を掲載しています。また、日本語のレジスタ名とビット名は、英語の定義名称を適当に訳してます。

  • USART データレジスタ (UDR)

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0

    送受信データを格納するデータレジスタです。本レジスタを読むことで、受信データバッファ内のデータを読み込むことができます。また、本レジスタに書き込むことで送信バッファにデータが書き込まれます。

    送信バッファに書き込まれたデータは、送信シフトレジスタというレジスタが空くとそこに送られ、その後 TXD ピンに出力されます。送信バッファへの書き込みは、口述する UCSRA レジスタの UDRE フラグに 1 が設定されている時のみ可能です。それ以外は書き込んだデータは無視されます。

    本レジスタは 8 ビット幅であるため、9 ビットデータを送受信する場合には上位 1 ビットを後述する UCSRB レジスタ内のビットとやりとりしなければなりません。

  • USART 制御/状態レジスタA (UCSRA)

    ビット番号 7 6 5 4 3 2 1 0
    マクロ RXC TXC UDRE FE DOR PE U2X MPCM
    初期値 0 0 1 0 0 0 0 0

    各ビットの説明を以下に書きます。

    ビット名 内容
    RXC(受信完了フラグ) 受信バッファ内にまだ読んでいないデータがある場合に 1 が設定され、UDR を読み込むことで空になると 0 になります。
    TXC(送信完了フラグ) 送信バッファ内にデータが無い場合に 1 が設定されます。送信完了割り込み時に自動的に 0 となる他、1 を書き込むことで 0 となります。
    UDRE(送信データレジスタ空きフラグ) 送信バッファが空でデータ受取準備が完了している場合に 1 が設定されます。
    FE(フレーミングエラーフラグ) フレーミングエラー発生時に 1 が設定されます。UDR を読むとクリアされてしまうため、UDR を読む前にエラー判定が必要です。また、UCSRA への書き込みを行う場合は、本ビットをあらかじめ 0 に設定する必要があります。
    DOR(データオーバランフラグ) データオーバラン発生時に 1 が設定されます。FE 同様 UDR を読むとクリアされます。また、UCSRA に書き込みを行う場合は本ビットをあらかじめ 0 に設定してください。
    PE(パリティエラーフラグ) パリティエラー発生時に 1 が設定されます。FE 同様 UDR を読むとクリアされます。また、UCSRA に書き込みを行う場合は本ビットをあらかじめ 0 に設定してください。
    U2X(倍速許可) 1 を書き込むと、非同期動作時にボーレートが自動的に 2 倍に設定され、非同期通信時のデータ転送速度が倍になります。同期通信時は 0 に設定します。
    MPCM(マルチプロセッサ通信動作) 1 を書き込むと、マルチプロセッサ通信動作が有効となります。マルチプロセッサ通信動作とは、複数の ATmega8535 の USART をシリアルバスで接続した場合に、アドレス情報をフレームに含めることで相手を指定して通信することができる動作です。この場合、アドレス情報を含まないフレームは破棄されます。


  • USART 制御/状態レジスタB (UCSRB)

    ビット番号 7 6 5 4 3 2 1 0
    マクロ RXCIE TXCIE UDRIE RXEN TXEN UCSZ2 RXB8 TXB8
    初期値 0 0 0 0 0 0 0 0

    各ビットの説明を以下に書きます。

    ビット名 内容
    RXCIE(受信完了割り込み許可) 1 を設定すると、受信完了を知らせる割り込みが有効になります。
    TXCIE(送信完了割り込み許可) 1 を設定すると、送信完了を知らせる割り込みが有効になります。
    UDRIE(送信データレジスタ空き割り込み許可) 1 を設定すると、送信データレジスタ空きを知らせる割り込みが有効になります。
    RXEN(受信許可) 1 を設定することで、USART によるデータ受信が有効になります。RXD ピン(14番ピン) は入出力ピン PORTD0 との兼用ピンですが、RXEN に 1 を設定すると PORTD0 の動作が無効となります。
    TXEN(送信許可) 1 を設定することで、USART によるデータ送信が有効になります。TXD ピン(15番ピン) は入出力ピン PORTD1 との兼用ピンですが、TXEN に 1 を設定すると PORTD1 の動作が無効となります。
    UCSZ2(データビット長選択2) 後述する UCSRC レジスタの UCSZ1/UCSZ0 ビットと合せた 3 ビットで、送受信データビット数を決定します。
    RXB8(受信データビット8) 送受信データビットが 9 の場合に、受信データの上位 1 ビットがここに格納されます。本ビットを読んだ後に、UDR から下位 8 ビットを読んでください。
    TXB8(送信データビット8) 送受信データビットが 9 の場合に、送信データの上位 1 ビットをここに格納します。UDR に下位 8 ビットを書き込む前に本ビットに書き込んでください。


  • USART 制御/状態レジスタC (UCSRC)

    ビット番号 7 6 5 4 3 2 1 0
    マクロ URSEL UMSEL UPM1 UPM0 USBS UCSZ1 UCSZ0 UCPOL
    初期値 1 0 0 0 0 1 1 0

    UCSRC レジスタは後述する UBRHH レジスタとアドレスが重なる様です。UCSRC に書き込みを行う場合、最上位ビット(URSEL)は 1 としなければなりません。URSEL が 0 となる値を UCSRC に書き込もうとしても、実際には UBRHH に書き込まれてしまいます。また UCSRC の内容を読み込む場合は、まず UBRRH を読み込み、次のクロックサイクルで UCSRC を読み込まないといけない様です。UBRHH と UCSRC の読み込みは連続していなければいけないため、途中で割り込み等が起きない様にしなければなりません。

    各ビットの説明を以下に書きます。

    ビット名 内容
    URSEL(レジスタ選択) UCSRC 書き込み時に 1 とすることで、UCSRC への書き込みを指定します。また、UCSRC の読み込み時には 1 となっています。
    UMSEL(動作モード選択) 0 を設定すると USART 非同期動作、1 を設定すると USART 同期動作が選択されます。
    UPM1/UPM0(パリティ動作選択) 組み合わせによってパリティ動作を決定します。

    UPM1 UPM0 動作内容
    0 0 無効
    0 1 将来用の予約値
    1 0 偶数パリティ
    1 1 奇数パリティ

    USBS(ストップビット数選択) 0 を設定するとストップビット数が 1 ビットに、1 を設定するとストップビット数が 2 ビットになります。
    UCSZ1/UCSZ0(データビット長選択) UCSRB レジスタの UCSZ2 ビットと合せて、データビット長を決定します。

    UCSZ2,1,0 データビット長
    0,0,0 5ビット
    0,0,1 6ビット
    0,1,0 7ビット
    0,1,1 8ビット
    1,0,0/1,0,1/1,1,0 将来用の予約項目
    1,1,1 9ビット

    UCPOL(クロック極性選択) 同期動作時に適用され、同期クロック(XCK、1番ピン(PORTB0 との兼用ピン))とデータ送受信動作の関係を設定します。

    UCPOL 送信データ送出 受信データ取得
    0 XCK の立ち上がりエッジ XCK の立ち下がりエッジ
    1 XCK の立ち下がりエッジ XCK の立ち上がりエッジ


  • USART ボーレートレジスタ (UBRRH、UBRRL)

    UBRR レジスタは、USART のボーレート(転送速度、ビット/sec)を基に計算した値(ボーレート分周値と呼ぶらしい?)を設定するためのレジスタです。値は 12 ビットで表現され、上位 4 ビットを UBRRH レジスタに、下位 8 ビットを UBRRL レジスタに書き込みます。ボーレート分周値は、以下の様にして計算します。

    動作種別 ボーレート分周値
    非同期動作(標準速度) (システムクロック周波数/(16 x ボーレート)) - 1
    非同期動作(倍速 U2X=1) (システムクロック周波数/(8 x ボーレート)) - 1
    同期動作 (システムクロック周波数/(2 x ボーレート)) - 1

    --- UBRRH ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ URSEL 予約 予約 予約 - - - -
    初期値 0 0 0 0 0 0 0 0

    UCSRC の所で説明した様に、UBRRH レジスタは UCSRC とアドレスが重なっています。UBRRH に書き込みを行う場合は、最上位ビット(URSEL) は 0 としなければなりません。URSEL が 1 となる値を UBRRH に書き込もうとしても、実際には UCSRC に書き込まれてしまいます。

    各ビットの説明を以下に書きます。

    ビット名 内容
    URSEL(レジスタ選択) UCSRC 書き込み時に 1 とすることで、UCSRC への書き込みを指定します。また、UCSRC の読み込み時には 1 となっています。
    ビット3 - ビット0(ボーレート分周値) ボーレート分周値の上位 4 ビットを設定します。

    --- UBRRL ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0

    各ビットの説明を以下に書きます。

    ビット名 内容
    ビット7 - ビット 0(ボーレート分周値) ボーレート分周値の下位 8 ビットを設定します。

○ 回路図

LECTURE 1 ATmega8535 および使用環境について に掲載してある全体回路図に対して、ATMega8535 の RXD/TXD ピン、ADM3202(RS-232ライン・ドライバ/レシーバ) および D-SUB 9 ピンコネクタ部分を赤枠で囲んだ図をこちらに置いておきます。

ATmega8535 の RXD/TXD をそれぞれ ADM3202 の R1OUT/T1IN に接続し、ADM3202 の R1IN/T1OUT を D-SUB 9 ピンコネクタに接続しています。これにより、PC からのデータは ADM3202 の R1IN -> ATmega8535 の RXD と入り、ATmega8535 からのデータは ATMega8535 の TXD -> ADM3202 の T1IN -> ADM3202 の T1OUT -> PC と流れます。

○ サンプルプログラムと説明

USART を使ってシリアル通信を行うサンプルプログラムを 03usart.tar.gz からダウンロードできます。はじめに のページから、全てのサンプルプログラムを 固めた tar ファイルをダウンロードすることもできます。

中には

  • Makefile
  • util.h
  • util.c
  • usart.h
  • usart.c
  • main-int.c (受信完了割り込み使用時の main)
  • main-noint.c (受信完了割り込み未使用時の main)

が格納されています。util.h/util.c については LECTURE 2 LED を点滅させる の内容と同じで、Makefile はターゲットが増えていますがもほとんど変わらないので、それ以外について以下に載せます。なお、以下に掲載しているソースコードには修正 BSD ライセンス条項を含めていませんが、ソースコード配布は修正 BSD ライセンスに従います(はじめに のページの免責事項を参照してください)。

これまでにヒューズビットの設定を行ったことが一度も無い場合は、まず最初に make fuse を実行してください。fuse ターゲットについては、LECTURE 2 LED を点滅させる のサンプルプログラムの項を参照してください。

make 実行後、割り込みを使用したプログラムをアップロードする場合は make uisp-int を実行してください。また、割り込みを使用していないプログラムをアップロードする場合は make uisp-noint を実行してください。実装方法が異なるだけで動作内容は同じです。

本サンプルプログラムは、以下のパラメータで通信を行います。

  • 非同期動作
  • ボーレート 9600 bps
  • パリティ無し
  • ストップビット 1ビット
  • 8 ビットデータ転送

実験用回路と PC のシリアルポート(D-SUB 9ピン)をストレートケーブルで接続してください。Windows であればハイパーターミナル等の通信ソフトで上記パラメータを設定し、フロー制御無しで接続します。PC 側で何かキーを押すと、"Received data = " という表示に続いて押したキーの文字が表示されます。表示文字が無いキー(Tab 等)を押すと文字部分には何も表示されません。

↓実験用基板とノートPC をシリアルケーブルで接続している所
ノートPCとシリアルケーブルで接続

↓通信ソフトにはこの様に表示されます。
シリアル通信中

  • usart.h
        1    #ifndef ___USART_H_INCLUDED_
        2    #define ___USART_H_INCLUDED_
        3    
        4    #include <inttypes.h>
        5    
        6    
        7    /* 割り込み使用/非使用選択マクロ */
        8    #define USART_NO_INT  0
        9    #define USART_USE_INT 1
       10    
       11    
       12    void usart_set_rx_interrupt(void (*func)(void));
       13    void usart_init(int use_interrupt);
       14    int8_t usart_rx_char(void);
       15    void usart_tx_char(int8_t c);
       16    void usart_tx_string(char *string);
       17    
       18    
       19    #endif
       20    
       21    /* End of usart.h */
    
    
    • 4 行目

      avr-libc のヘッダファイル inttypes.h をインクルードしています。int8_t 等のサイズ指定型を使用するために必要です。

    • 7 〜 9 行目

      usart_init() にて、受信完了通知割り込みを使用するかどうかを指定するためのマクロ定義です。

  • usart.c
        1    #include <avr/interrupt.h>
        2    #include <avr/io.h>
        3    #include <inttypes.h>
        4    
        5    #include "usart.h"
        6    
        7    
        8    /* ボーレート */
        9    #define USART_BAUD 9600 
       10    
       11    
       12    static void (*rx_interrupt_handler)(void);
       13    
       14    
       15    /*
       16     * 受信完了時割り込みハンドラ
       17     * usart_init(USART_USE_INT) とした場合に有効となる。
       18     */
       19    ISR(USART_RX_vect)
       20    {
       21            rx_interrupt_handler();
       22    }
       23    
       24    
       25    /*
       26     * 受信完了時割り込みハンドラ内で実行する
       27     * ユーザ関数を設定する。
       28     */
       29    void
       30    usart_set_rx_interrupt(void (*func)(void))
       31    {
       32            rx_interrupt_handler = func;
       33    }
       34    
       35    
       36    /*
       37     * USART 通信パラメータを 9600bps/8N1 に設定する。
       38     *
       39     * 受信完了時割り込みを使用する場合、本関数実行後に 
       40     * sei() を実行することで有効となる。
       41     */
       42    void
       43    usart_init(int use_interrupt)
       44    {
       45            /* ボーレート設定( (F_CPU/(16*BAUD)) - 1 で計算する ) */
       46            uint16_t baud = (F_CPU / (16UL * USART_BAUD)) - 1;
       47    
       48            UBRRH = (uint8_t)(baud >> 8);
       49            UBRRL = (uint8_t)baud;
       50    
       51            if (use_interrupt) {
       52                    /* Tx/Rx/受信完了時割り込みを有効化 */
       53                    UCSRB = _BV(TXEN) | _BV(RXEN) | _BV(RXCIE);
       54            }
       55            else {
       56                    /* Tx/Rx を有効化 */
       57                    UCSRB = _BV(TXEN) | _BV(RXEN);
       58            }
       59    }
       60    
       61    
       62    /*
       63     * 1 文字受信処理
       64     * フレームエラーおよびオーバラン発生時は -1 を返す。
       65     */
       66    int8_t
       67    usart_rx_char(void)
       68    {
       69            loop_until_bit_is_set(UCSRA, RXC); /* 1 になったら受信完了 */
       70    
       71            if ((UCSRA & _BV(FE)) || (UCSRA & _BV(DOR))) {
       72                    return -1;
       73            }
       74    
       75        return UDR;
       76    }
       77    
       78    
       79    /*
       80     * 1 文字送信処理
       81     */
       82    void
       83    usart_tx_char(int8_t c)
       84    {
       85            loop_until_bit_is_set(UCSRA, UDRE); /* 1 になったら送信可能 */
       86            UDR = c;
       87    }
       88    
       89    
       90    /*
       91     * 文字列送信処理
       92     */
       93    void
       94    usart_tx_string(char *string)
       95    {
       96            while (*string != '\0') {
       97                    usart_tx_char(*string);
       98                    string ++;
       99            }
      100    }
      101    
      102    
      103    /* End of usart.c */
    
    
    • 1 行目

      ここでインクルードしている avr/interrupt.h は、19 行目で使用している割り込みハンドラ定義のために必要です。

    • 8 〜 9 行目

      本プログラムが使用するボーレートを 9600 bps 固定として定義しています。

    • 15 〜 22 行目

      受信完了通知割り込みを有効にした場合に使用する、割り込みハンドラを記述しています。 avr-libc を使う場合、割り込みハンドラは以下の様に宣言します。

      ISR(割り込み種別を表すマクロ)
      {
              /* 割り込みハンドラの実処理をここに記述する */
      }
      
      

      割り込み種別を表すマクロは、avr/interrupt.h に定義されています。ここでは、ATmega8535 の USART 受信完了割り込みを表す USART_RX_vect を指定しています。実際には後述する usart_set_rx_interrupt() で登録されたユーザ関数を実行する様に実装しています。

    • 25 〜 33 行目 (usart_set_rx_interrupt())

      前述の USART 受信完了割り込みハンドラ内で実際に実行する、ユーザ関数を登録します。

    • 36 〜 59 行目 (usart_init())

      USART 機能の初期化を行います。最初に 関連レジスタ にて説明している式を使ってボーレートに対応した UBRR 値を計算し、UBRRH / UBRRL に設定します。 他の設定用レジスタについてはデフォルトで

      • 非同期動作
      • パリティ無し
      • ストップビット 1 ビット
      • 8 ビットデータ転送

      であるため、UCSRB レジスタの TXEN / RXEN ビットを 1 とすることで USART 送受信を有効にしています。 受信完了通知割り込みを有効にする場合は、併せて RXCIE を 1 とすることで有効にしています。 実際にはこれだけでは受信完了通知割り込みは送信されず、avr/interrupt.h で定義されている sei() 関数を実行することで、割り込みそのものを有効とする必要があります。

    • 62 〜 76 行目 (usart_rx_char())

      受信バッファから 1 データを取得します。 まず UCSRA レジスタの RXC ビットが 1(受信バッファに未読データ有り)になるまで待ちます。 loop_until_bit_is_set(sfr, bit) は、sfr レジスタの bit 番ビットが 1 となるまでループして待つマクロです。 avr/io.h をインクルードすれば使えます。

      受信完了を検出したら、データを読みだす前に UCSRA レジスタの FE および DOR ビットを調べて データオーバランやフレーミングエラーが発生していないかどうか確認しています。 いずれかを検出した場合は -1 を返しています。本関数ではエラー種別は区別していません。

      エラーが発生していなければ、UDR レジスタの値を読むことで受信バッファからデータを取得して終了します。

    • 79 〜 87 行目 (usart_tx_char())

      送信バッファに対して 1 データを設定します。まず UCSRA レジスタの UDRE ビットが 1 (送信バッファが空)になるまで待ちます。送信バッファが空になったのを検出したら、UDR に値を書き込むことで送信バッファにデータを設定して終了します。

    • 90 〜 100 行目 (usart_tx_string())

      文字列送信用の関数です。1 文字ずつ usart_tx_char() を使って送信しているだけです。

  • main-int.c(受信完了割り込み使用時の main)
        1    #include <avr/interrupt.h>
        2    #include <avr/sleep.h>
        3    #include <inttypes.h>
        4    
        5    #include "usart.h"
        6    #include "util.h"
        7    
        8    
        9    static void rx_interrupt(void);
       10    
       11    
       12    int
       13    main(void)
       14    {
       15            pullup();
       16            usart_init(USART_USE_INT);
       17            usart_set_rx_interrupt(rx_interrupt);
       18            sei();
       19    
       20            while (1) {
       21                    sleep_mode();
       22            }
       23    
       24            return 0; /* 警告を避けるため */
       25    }
       26    
       27    
       28    static void
       29    rx_interrupt(void)
       30    {
       31            char buf[20] = "Received data =  \r\n";
       32            int index = 16;
       33    
       34            int8_t recv_data = usart_rx_char();
       35    
       36            if ( recv_data == -1 ) {
       37                    usart_tx_string("Unknown data...\r\n");
       38                    return;
       39            }
       40    
       41            buf[index] = recv_data;
       42            usart_tx_string(buf);
       43    }
       44    
       45    /* End of main-int.c */
    
    

    本ファイルは、受信完了割り込みを使って受信処理を行う場合の main() を記述しています。

    • 12 〜 25 行目 (main())

      • pullup() (pullup.h、全入力ポートの内部プルアップを有効化)
      • usart_init() (usart.h、USART 初期化)
      • usart_set_rx_interrupt() (usart.h、受信完了割り込み時に実行するユーザ関数の登録)

      を行った後、avr/interrupt.h で定義されている sei() を実行してシステムの割り込みを有効化しています。 これにより USART 部がデータを受信する度に、後述する rx_interrupt() が実行されます。

      以後、USART の送受信処理は rx_interrupt() の中で行うため、20 〜 22 行目は無限ループとなっています。 21 行目の sleep_mode() は、AVR をスリープ状態に移行するための関数です。avr/sleep.h をインクルードすると使えます。スリープ状態には数種類有り、必要ならば set_sleep_mode() で前もって指定しておく必要があります。

      #include <inttypes.h>
      #include <avr/sleep.h>
      
      void set_sleep_mode(uint8_t mode);
      void sleep_mode(void);
      
      

      set_sleep_mode() に指定できる値は以下のいずれかです。

      スリープ動作種別
      SLEEP_MODE_IDLE アイドル動作
      SLEEP_MODE_ADC A/D 変換ノイズ低減動作
      SLEEP_MODE_PWR_DOWN パワーダウン動作
      SLEEP_MODE_PWR_SAVE パワーセーブ動作
      SLEEP_MODE_STANDBY スタンバイ動作
      SLEEP_MODE_EXT_STANDBY 拡張スタンバイ動作

      それぞれの動作種別の詳細についてはデータシート等をご覧ください。 本サンプルでは何も指定していないため、SLEEP_MODE_IDLE を指定したのと同じ状態になります。

    • 28 〜 43 行目 (rx_interrupt())

      まず usart_rx_char() で受信バッファからデータを取得します。受信完了割り込みハンドラ内であり UCSRA レジスタの RXC ビットが設定されているため、usart_rx_char() はブロックせずにすぐ戻ります。 データオーバランやフレーミングエラー発生時には "Unknown data..." という文字列を usart_tx_string() で送信バッファに設定して終了します。有効な受信データがある場合は、 "Received data = ..." という文字列を作成して usart_tx_string() で送信バッファに設定しています。

      ところで avr-libc には sprintf() / snprintf() 等があるのですが、本プログラムでは 受信データを直接文字バッファに格納して文字列を作成しています。 sprintf() 等を使いたかったのですが、いざ使って avr-libc とリンクしてみたら、 アップロード用のバイナリファイルが ATmega8535 のフラッシュメモリサイズである 8 KB をあっさり超えてしまいました(最適化有りでも)。ので使ってません。 自分が勘違い等していて、実は 8 KB 以内に収める方法があるのかもしれません。 お気づきの方はぜひ教えてください…

  • main-noint.c(受信完了割り込み未使用時の main)
        1    #include <inttypes.h>
        2    
        3    #include "usart.h"
        4    #include "util.h"
        5    
        6    
        7    int
        8    main(void)
        9    {
       10            char buf[20] = "Received data =  \r\n";
       11            int index = 16;
       12    
       13            pullup();
       14            usart_init(USART_NO_INT);
       15    
       16            while (1){
       17                    int8_t recv_data = usart_rx_char();
       18        
       19                    if (recv_data == -1) {
       20                            usart_tx_string("Unknown data...\r\n");
       21                            continue;
       22                    }
       23    
       24                    buf[index] = recv_data;
       25                    usart_tx_string(buf);
       26            }
       27    
       28            return 0; /* 警告を避けるため */
       29    }
       30    
       31    /* End of main-noint.c */
    
    

    本ファイルは、受信完了割り込みを使わずに受信処理を行う場合の main() を記述しています。

    • 7 〜 29 行目 (main())

      • pullup() (pullup.h、全入力ポートの内部プルアップを有効化)
      • usart_init() (usart.h、USART 初期化)

      を行った後、while ループに入ります。ループ内の処理は、main-int.c の rx_interrupt() における処理と同じです。ただし、main-noint.c の場合は、usart_rx_char() は受信バッファにデータが格納されるまでブロックします。

以上で解説は終わりです。PC から自分が作った基板に対して通信を試みてうまく通信できると、結構楽しいですよ…