mbedのSerial通信

# 必要なこと

* インクルード

```
#include "Serial.h"
```

* インスタンス生成

```
Serial pc(USBTX, USBRX); // USBシリアルポートのインスタンス
Serial インスタンス名(p28,p27);      //　RX,TXでのシリアルポート生成
```
* ボーレート調整

```
pc.baud(115200);
インスタンス名.baud(115200);
```

* pcに送る

```
int data = 1;
pc.printf("hello %5d \r\n",data);
```

# 概要
`mbed`で`Serial`通信を利用する一番の利点は、<font color = Red>Serial受信割り込み</font>がある事でしょう。
`Arduino`には有りません。

さらに`USB`も入れると$4$つもポートがあるので、センサーとの通信を全て`Serial`でまとめておくと、`I2C`や`SPI`での通信失敗やデータの送信受信不一致を避けることができてとても楽です。特に`mbed`は`SPI`割り込みを持たないので、やはり`Serial`でしょう。


通信速度については、$115200bps$も有れば、$1$秒に$14400byte$もデータが送れるので速度で困ることはほぼないでしょう。
ただし、送信処理`printf`に食われるmbedの処理時間はとても長いです。これは、`printf`では$1byte$で$10$進数の$1$桁のみを送ることになるためです。よって、送信する場合は`printf`でなく`putc(char)`を使って、`ASCIIコード`に変換せず$1$byte$データとして送信するのが良いと思われます。

# 受信方法
受信する方法は、`Serial受信割り込み処理`をセットして

```C++
Serialインスタンス.attach(受信割り込み関数,Serial::RxIrq);
```
割り込み処理内で

```C++
char receive = Serialインスタンス.getc();
```
をすることで$1$byteデータを読むことができます。

### 受信サンプルプログラム

```C++
Serial pc(USBTX, USBRX); // USBシリアルポートのインスタンス生成
Serial Cc(p28,p27);
void getC(){
    //受信割り込み処理
    char receive = Cc.getc();
}
int main() {
    pc.baud(115200);
    Cc.baud(115200);
    Cc.attach(getC,Serial::RxIrq);        //受信割り込み関数getC(名前は何でも良い)を設定
    while (1) {
        
    }
}
````

受信したデータをpcに送る場合は次のように受信割り込み関数を変更します。

```C++
void getC(){
    char receive = Cc.getc();
    int data = (int)receive;
    pc.printf("%5d \r\n",data);
}
```

送信側は$1$byteデータを送信させます。

<!--
### 2byte以上送る場合
最上位bitの値で上位byte、下位byteの区別をつけることで2byte送る方法

```C++
void getR()
{
    //pc.printf("%c ",Ro.getc());
    char Rse = Ro.getc();
    if((Rse&0b10000000)==0b10000000) { //highByte
        high = Rse ;
        if((high&0b01000000)==0b01000000) {  //値は負なのでそのまま
            Polarity = true;
        } else {                              //値は正なので最上位を0にする
            high= high & 0b01111111;
            Polarity = false;
        }
        //pc.printf("%3x high",Rse);
    } else {                           //lowByte
        low = Rse;
        //pc.printf("%3x low",Rse);
        Rotate = (high <<7) | low ;
        if(Polarity ==true ) {                //負の時 int 2byte でないので
            Rotate = Rotate|0x8000;
        }
        //pc.printf("%6d \r\n",Rotate);
    }
}
```
$14$bit（$\pm{8000}$程度）データの送受信、8bit目の数値を0,1で上位か下位かを区別してデータを変換し受け取っています。

-->

# 送信

基本的には

```C++
Serialインスタンス.putc(char);
```
で1byte送信できます。
数値データの場合は`char`型への変換が要ります。

```C++
int data = 3;
char send = (char)data;
Cc.putc(send);
```
これで1byteまでなら送信できます。

`data`は$0$から$255$までです。

```
char send = (char)data;
```
の変換は

```
-256 -> 0
-255 -> 1
-127 -> 129
-126 -> 130
-125 -> 131
-1   -> 255
0    ->  0
1    ->  1
125  ->  125
126  ->  126
127  ->  127
128  ->  128
255  ->  255
256  ->  0
```
に変わります。つまり、

```math
send = 
\left\{
\begin{array}{ll}
data & (255 \geq data \geq 0)\\
256+data &( 0 \geq data \geq -256)
\end{array}
\right.
```
となっています。
負の値を送るのは面倒そうですね。

2byte以上送るのも面倒です。
昔の自分は最上位ビットで頑張って送ってますが、たぶんそれ用のライブラリがあると思うので探してみてください。Arduinoには`Packet Serial`という超便利なライブラリがあります。

https://github.com/bakercp/PacketSerial

https://qiita.com/hideakitai/items/347985528656be03b620

`mbed`にもあれば教えて下さい。



# Serial受信割り込みとputcの併用の注意
2019/12/11:追記
受信割り込みを入れた場合、`putc(5);`のようなSerial送信は割り込み関数内に入れないと動作が不安定になります。
自動で再起動したりして、最初は困惑しました。

mbedには`USART`,`UART`の二つがあり、この違いが影響しているかも知れません。CPUの説明では`UART4,5`とあるので`UART`はSerial4,5のみです。

## 失敗するサンプルプログラム

```C++
#include "mbed.h"
 
Serial pc(USBTX, USBRX); // USBシリアルポートのインスタンス
Serial moterDriver(PC_10,PC_11);    

void geCC(){
    int k2=moterDriver.getc();
}

int main() {
    
    pc.baud(115200);
    moterDriver.baud(115200);
    moterDriver.attach(geCC,Serial::RxIrq);
    
    while(1) {
       moterDriver.putc(3);       //送信を受信割り込み外で行う
       pc.printf("moving\r\n");
    }
}
```
このプログラムを動かしている時に、`PC_10,PC_11`ピンに`Serial`データを送信すると、常時送信していた文字列"moving"が停止します。
恐らく、送信中に受信割り込みが入るのは想定外なんでしょう。

 `tx,rx`電圧レベルの問題ではない事は、オシロで計測して確認しました。`Nucleo F446RE`で確認しました。`LPC1768`でも、似たプログラムを使っている際に頻繁に落ちて困ってしまったので仕様だと思われます。

`putc`を利用する際は安全のため、その`Serial`受信割り込み処理内に`putc`を置いた方が良いかもしれません。