可変ブログ

色々メモとか。とりあえず自分が分かるように。その後、なるべく人が見て分かるように。可変。

Arduinoで外部割込みとシリアル割り込み

・外部割込み

簡単なスケッチを

#define INT_PIN 2

void gpio_isr(){
  Serial.println("warikomi");
}


void setup() {
    Serial.begin(115200);
    
    pinMode(INT_PIN, INPUT); // 割り込みのためのピンを設定
    attachInterrupt(digitalPinToInterrupt(INT_PIN), gpio_isr, FALLING);  // 割り込み開始
}

void loop(){
}

pinMode()で割り込みに使うピンを入力に設定
attachInterrupt() で割り込みに使うピンとコールバック関数とピンの状態がどういうときに割り込みを発生させるかを設定。
ピンは普通のピン番号と割り込みに使うピン番号は違うらしいのでdigitalPinToInterrupt() で変換



・シリアル割り込み
void serialEvent() { } という名前でやりたい処理の関数を定義します。
ただ、割り込みと言っても loop()関数が一周したあとにserialEvent() が実行されているだけなので、割り込みっぽくないです。



ArduinoとEthernetシールドを使ってTCP通信

ArduinoEthernetシールドの互換品を使ってTCP通信をします。
今はEthernetシールド2というものがあるらしいですが、今回使用するのは1の方だと思います。(たぶん)
Ethernetシールド2の場合、使うライブラリやArduinoIDEのバージョンが変わってくるので注意してください。
ちなみに純正品はもう1も2も生産していないらしいです。

使ったシールドはこれ




ここを参考に。



簡単なスケッチを。

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below. The IP address will be dependent on your local network:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 177);

// Initialize the Ethernet server library with the IP address and port you want to use (port 80 is default for HTTP):
EthernetServer server(19227);
EthernetClient client;

char eth_recv_buf[128];
char eth_send_buf[37] = "M SD8 124 01 23 45 67 89 AB CD EF \r\n";
char eth_recv_len;
char eth_send_len;


void EthWrite(){
    if (Serial.available()){
        one_char = Serial.read();
        if (one_char == 'M'){
            serial_itr = 0;
        }

        serial_recv_buf[serial_itr] = one_char;

        if ((one_char == '\n') && (serial_itr == 35)){
            client.write(serial_recv_buf, 36);
        }
        if ((++serial_itr) > 36) {
            serial_itr = 0;
        }
    }
}


void setup() {
    // Open serial communications and wait for port to open:
    Serial.begin(115200);
    while (!Serial) { ; }

    Ethernet.init(10);  // Most Arduino shields
    Ethernet.begin(mac, ip);

    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
        while (true) {
            delay(1); // do nothing, no point running without Ethernet hardware
        }
    }

    // start the server
    server.begin(); // listen相当

    pinMode(8, OUTPUT);
}

char c;
void loop() {
    // listen for incoming clients
    client = server.available(); // accept相当
    if (client) {
        while (client.connected()) {
            if (eth_recv_len = client.available()) {
                digitalWrite(8, HIGH);
                c = client.read(eth_recv_buf, eth_recv_len);
                Serial.write(eth_recv_buf, eth_recv_len);
            }
            
            EthWrite();
            digitalWrite(8, LOW);
        }

        delay(100);
        client.stop();
    }
}

Ethernet.init() はイーサネットシールドとのSPI通信につかうCSピンです。
server.available() でクライアントの接続を待ちます。
client.available() で受信したByte数を取得してそのByte数だけclient.read()で読み出します。



その他参考




TCPとUDPの違い

TCP
送信したパケットは勝手に分割されて適当に結合されて受信される(データの境界保証なし)
つまり1回send() ≠1回recv()

送信したデータが受信されないと送信側はブロッキングする。
つまり、通信状況が悪いと送信タイミングのリアルタイム性が損なわれる。




UDP
送信したパケットは勝手に分割されないが、あまりデータが大きいとIPフラグメンテーションされる可能性がある。(パケット分割とIPフラグメントは別物らしい)
その場合受信側でデータがすべて出揃うまで受信を完了しない。(データの境界保証あり)
つまり1回send() =1回recv()
また、データがいつまでたっても揃わなかったらそのデータは破棄される。

send()したデータの順番とrecv()したデータの順番が入れ替わる可能性がある。
送信側は受信側がちゃんと受信できたか確認しないで構わず送信し続けるため、
通信状況が悪くても送信タイミングのリアルタイム性が損なわれない。




IPフラグメンテーション




UEFIブートのエントリを削除する方法

間違ったところにブートローダーを書き込んでしまった時に



windowsから削除


linuxから削除




windowsデュアルブートでOSの選択画面が出てこないとき

MCP2515を使ってArduinoでCAN通信

MCP2515のモジュールを使ってArduinoでCAN通信をさせる。
ライブラリはMPC_CAN_libを使う。
スケッチの書き方は、MPC_CANのgithubのサンプルプログラムとヘッダを見るとわかりやすい。




・ハマったところ1
MCP_CAN::begin() が変更されてて、引数にいろいろ指定しなければいけなくなっていた。
何を指定しなければいけないかはサンプルプログラムとヘッダを見て判断した。
第1引数:IDの種類
第2引数:canの通信速度
第3引数:モジュールとの通信レート(今回の場合はモジュールの水晶発振子の周波数)


・ハマったところ2
MCP_CAN::setMode() が抜けてた



簡単なArduinoスケッチ
以下のソースではif(!digitalRead(INT_PIN))の部分でモジュールからの割り込みをポーリングしているが、
モジュールの割り込み用ピンをArduinoの外部割込み(ハードウェア割り込み)に割り当てて、
割り込み処理したほうが効率がいいと思う。

// ライブラリヘッダのインクルード
#include <mcp_can.h>
#include <SPI.h>
 
//設定値
#define CS_PIN  (10) // CSを10ピンとする(変更可能)
#define INT_PIN (9)  // INTを9ピンとする(変更可能)
 
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

MCP_CAN CAN0(CS_PIN);      
 
void setup() {
    Serial.begin(115200);
    CAN0.begin(CAN_STDID, CAN_500KBPS, MCP_8MHZ); // CANの通信速度を500kbpsにする 
    pinMode(INT_PIN, INPUT); // 割り込みのためのピンを設定
    CAN0.setMode(MCP_NORMAL);
    Serial.println("MCP2515 Library Receive Example...");
}

byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};

void loop(){
    //受信
    if(!digitalRead(INT_PIN)) {  // 受信割り込みが発生したら、CANデータをReadする
        CAN0.readMsgBuf(&rxId, &len, rxBuf);
        Serial.print("ID: ");
        Serial.print(rxId, HEX);
        Serial.print("  Data: ");
        for(int i = 0; i<len; i++) {
            if(rxBuf[i] < 0x10) {
                Serial.print("0");
            }
            Serial.print(rxBuf[i], HEX);
            Serial.print(" ");
        }
        Serial.println();
    }


    //送信
    byte sndStat = CAN0.sendMsgBuf(0x122, 0, 8, data);
    if (sndStat != CAN_OK) {
        Serial.println("Error Sending Message...");
    }
    delay(100);   // send data per 100ms
}
 
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/