Arduinoで遊ぶページ

Arduinoで遊んだ結果を残すページです。
garretlab
Serial.begin()/HardwareSerial::begin()

HardwareSerial::begin()

概要

HardwareSerial::begin()は、シリアル通信を行う際の通信速度の設定や送受信の許可ビットの設定を行います。リファレンスはこちら

HardwareSerial::begin()では、UCSR0AUCSR0BUSCR0CUBRR0の3つのレジスタを操作します。

ソースコード

HardwareSerial::begin()は、hardware/arduino/cores/arduino/HardwareSerial.cppに定義されています。以下に全ソースコードを示します。

Arduino 1.0.2からは2種類のbegin()が定義されています。新しく追加されたbegin()は、USCR0Cを設定するためのコードが入っています。通常は使う必要はないと思います。

void HardwareSerial::begin(unsigned long baud)
{
  uint16_t baud_setting;
  bool use_u2x = true;

#if F_CPU == 16000000UL
  // hardcoded exception for compatibility with the bootloader shipped
  // with the Duemilanove and previous boards and the firmware on the 8U2
  // on the Uno and Mega 2560.
  if (baud == 57600) {
    use_u2x = false;
  }
#endif

try_again:
  
  if (use_u2x) {
    *_ucsra = 1 << _u2x;
    baud_setting = (F_CPU / 4 / baud - 1) / 2;
  } else {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }
  
  if ((baud_setting > 4095) && use_u2x)
  {
    use_u2x = false;
    goto try_again;
  }

  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  transmitting = false;

  sbi(*_ucsrb, _rxen);
  sbi(*_ucsrb, _txen);
  sbi(*_ucsrb, _rxcie);
  cbi(*_ucsrb, _udrie);
}

void HardwareSerial::begin(unsigned long baud, byte config)
{
  uint16_t baud_setting;
  uint8_t current_config;
  bool use_u2x = true;

#if F_CPU == 16000000UL
  // hardcoded exception for compatibility with the bootloader shipped
  // with the Duemilanove and previous boards and the firmware on the 8U2
  // on the Uno and Mega 2560.
  if (baud == 57600) {
    use_u2x = false;
  }
#endif

try_again:
  
  if (use_u2x) {
    *_ucsra = 1 << _u2x;
    baud_setting = (F_CPU / 4 / baud - 1) / 2;
  } else {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }
  
  if ((baud_setting > 4095) && use_u2x)
  {
    use_u2x = false;
    goto try_again;
  }

  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  //set the data bits, parity, and stop bits
#if defined(__AVR_ATmega8__)
  config |= 0x80; // select UCSRC register (shared with UBRRH)
#endif
  *_ucsrc = config;
  
  sbi(*_ucsrb, _rxen);
  sbi(*_ucsrb, _txen);
  sbi(*_ucsrb, _rxcie);
  cbi(*_ucsrb, _udrie);
}

入力はbaudで、unsigned longです。戻り値はありません。

void HardwareSerial::begin(unsigned long baud)
{
  uint16_t baud_setting;
  bool use_u2x = true;

引数のbaudが57600のときは、use_u2xをfalseにします。use_u2xはもともとtrueで初期化されています。

  if (baud == 57600) {
    use_u2x = false;
  }

baudとuse_u2xとをもとに、UBRRに設定する値を決定します。

try_again:
  
  if (use_u2x) {
    *_ucsra = 1 << _u2x;
    baud_setting = (F_CPU / 4 / baud - 1) / 2;
  } else {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }
  
  if ((baud_setting > 4095) && use_u2x)
  {
    use_u2x = false;
    goto try_again;
  }

ATmega328Pのデータシートによると、UBRRに設定する値は、以下の通りですが、

  1. U2Xn = 0のとき
    UBRRn = (F_CPU / (16 * BAUD)) - 1
  2. U2Xn = 1のとき
    UBRRn = (F_CPU / (8 * BAUD)) - 1

Arduinoでは、以下のように設定しています。

  1. U2Xn = 0のとき
    UBRRn = (F_CPU / 8 / baud - 1) / 2
  2. U2Xn = 1のとき
    UBRRn = (F_CPU / 4 / baud - 1) / 2

このためデータシートの値より0.5大きい値となっているようです。しかし、UBRRnは整数型の変数なので基本的には同じ数値になるようです。

例えば、baudが9600のときには、Arduino UnoではF_CPUは16000000なので、use_u2x=true、baud_setting=207となります。このときの通信速度は、約9615.385bpsとなります。

UBRRnの有効ビット数は12ビットなので、use_u2xがtrueかつbaud_settingが4095よりも大きくなった場合は、use_u2xをfalseにして再度計算を行います。

baud_settingが4095より大きくなるのは、baudが488以下の場合です。この場合は、use_u2xをfalseにして再計算します。use_u2xをfalseにしてもbaudが244以下になると、baud_settingは4095を超えてしまいます。この場合は、UBRRnに4096以上の数値が設定されてしまいますが、データシート上はUBRRnHの上位4ビットは0に設定するように書かれており、非推奨の使い方になるようです。わざわざこんな小さい値を設定する必要もありませんが。

configを設定したときには、ここで、configの値をそのまま、 レジスタに渡しています。また、configを設定しているときにはtransmittingの設定を行っていませんが、おそらく忘れているのだと思います。初期化もされていませんが、おそらく、falseで初期化されるので問題はないということだと思います。

  *_ucsrc = config;

最後に、transmittingをfalseにした後、レジスタを設定します。

  transmitting = false;

  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  sbi(*_ucsrb, _rxen);
  sbi(*_ucsrb, _txen);
  sbi(*_ucsrb, _rxcie);
  cbi(*_ucsrb, _udrie);
}

UBRRは通信速度を設定するレジスタです。計算したbaud_settingを設定します。

他に、USARTの受信許可(RXEn)、送信許可(TXEn)、RXCnフラグの割り込み許可(RXCIEn)、UDRIEnの割り込み禁止(UDRIEn)に設定します。

バージョン

Arduino 1.0.5



メニューを表示するためにJavaScriptを有効にしてください。

Arduinoで遊ぶページ
Copyright © 2012 garretlab all rights reserved.
inserted by FC2 system