1.概要
Rasberry Pi Pico(以下、Pico)とArduino Uno(以下、Uno)間のRS232C通信を試みました。マイコン間でしたら、UARTで直接シリアル通信出来るのかもしれませんが、PicoとUnoではロジック電圧が、異なること、想定する利用目的においてマイコン間の距離を確保したいことなどを理由にRS232C変換し、通信しています。
RS232Cレベル変換する為に、秋月電子から販売されているRS232Cレベル変換基板 [AE-ADM3202] を使用しています。通信に関係する接続は下図の通りです。Pico側ステッピングモータ接続は先回投稿と同じなので省略します。
2.動作内容
Rasberry Pi Pico は、先回投稿同様にL6470を介してステッピングモーターを制御します。①プログラム起動、②原点復帰完了、③原点復帰後に10秒間移動、④再度、原点移動 の各ステータスにてUno側にメッセージをシリアル送信します。
下図は、Rasberry Pi Picoから送信されたメッセージをUno側で受信した文字列を表示した状態です。意図した通りに送信されていることを確認出来ました。
3.プログラム
①Uno(受信)側プログラム
受信内容をシリアルモニターに出力します。受信データはASCIIコードなので、変換処理しています。
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX,TXの割り当て
char c_asc[] = " ! #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[ ]^_`abcdefghijklmnopqrstuvwxyz{|}~";
const int LED_PIN = 13;
// 初期設定
void setup(){
Serial.begin(9600); // シリアルモニター
mySerial.begin(9600); // ソフトウェアシリアル通信の開始(ボーレート9600bps)
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
}
void loop(){
int val_bf=0;
while(mySerial.available()>0){
int val = mySerial.read(); // 受信したデータを読み込む
if(val>31){
Serial.print(c_asc[val - 32]); // ASCコード32以上を対象
}
if (val_bf==13 & val==10){ // 改行コード
Serial.println("");
}
val_bf = val; // 改行コード CR LF 連続入力確認用
}
delay(100);
}
②Pico側プログラム(送信)
ステッピングモータを制御し、動作状況を通信します。
#include <SPI.h>
// ピン定義。
#define PIN_SPI_MOSI 19
#define PIN_SPI_SCK 18
#define PIN_SPI_SS 17
#define PIN_SPI_MISO 16
#define PIN_BUSY 20
#define PIN_LMT_ORG 21
#define PIN_LMT_END 22
#define PIN_LMT_LED 15
#define PIN_DRV_LED 14
int val_org = 0;
int val_end = 0;
int val_bsy = 0;
int sts_origin=0; // 原点復帰ステータス
// 起動時実行
void setup()
{
Serial1.begin(9600); // UART0初期化 TX:GP0 / RX:GP1
delay(1000);
pinMode(PIN_SPI_MOSI, OUTPUT); // SPI送信
pinMode(PIN_SPI_MISO, INPUT); // SPI受信
pinMode(PIN_SPI_SCK, OUTPUT); // SPIクロック
pinMode(PIN_SPI_SS, OUTPUT); // SPIスレーブセレクト
pinMode(PIN_BUSY, INPUT); // L6470 BUSY
pinMode(PIN_LMT_ORG, INPUT_PULLUP); // 原点SW入力
pinMode(PIN_LMT_END, INPUT_PULLUP); // 駆動端SW入力
pinMode(PIN_LMT_LED, OUTPUT); // LED出力
pinMode(PIN_DRV_LED, OUTPUT); // LED出力
SPI.begin();
SPI.setDataMode(SPI_MODE3);
SPI.setBitOrder(MSBFIRST);
digitalWrite(PIN_SPI_SS, HIGH);
L6470_rst_device(); // L6470リセット
L6470_set_parameter(); // L6470設定
delay_checking_sw_input( 500 );
Serial1.println("Program Start!");
}
// メインループ
void loop(){
val_org = !digitalRead(PIN_LMT_ORG); // 入力ピンを読む
val_end = !digitalRead(PIN_LMT_END); // 入力ピンを読む
val_bsy = digitalRead(PIN_BUSY);
int val_tmp = !digitalRead(TMP_2) | !digitalRead(TMP_3) | !digitalRead(TMP_4) | !digitalRead(TMP_5);
digitalWrite(PIN_LMT_LED, val_org | val_end | val_tmp);
digitalWrite(PIN_DRV_LED, val_bsy);
if (sts_origin==0){
get_origin(); // 原点復帰
sts_origin=1;
Serial1.println("NESTING FINISHED");
L6470_data_transfer(0x51,3,8000); // 反-原点中速移動
delay_checking_sw_input( 10000 );
Serial1.println("MOVED 10SEC");
L6470_data_transfer(0xb0,0,0); // 停止(トルク保持)
L6470_wait_not_busy( 2000 );
L6470_data_transfer(0x60,3,0); // 絶対値移動(原点(0))
L6470_wait_not_busy( 500 );
Serial1.println("HOME POSITION");
}
}
// 原点復帰動作
void get_origin(){
if(!digitalRead(PIN_LMT_ORG)){
L6470_data_transfer(0x51,3,8000);
// 反-原点方向(右)中速移動
delay_checking_sw_input( 100 );
while(!digitalRead( PIN_LMT_ORG )){ }
delay_checking_sw_input( 1000 );
L6470_data_transfer(0xb0,0,0);
// 回転停止(トルク保持)
L6470_wait_not_busy(500);
}
// 原点方向(左)中速移動
L6470_data_transfer(0x50,3,8000);
while(digitalRead( PIN_LMT_ORG )){}
// 回転停止、保持トルクあり
L6470_data_transfer(0xb0,0,0);
L6470_wait_not_busy(500);
// 反-原点方向(右)低速移動
L6470_data_transfer(0x51,3,500);
delay_checking_sw_input( 50 );
while(!digitalRead( PIN_LMT_ORG )){}
// 回転停止(トルク保持)
L6470_data_transfer(0xb0,0,0);
L6470_wait_not_busy(500);
// 反-原点方向(右)長さ指定移動
L6470_data_transfer(0x41,3,600);
L6470_wait_not_busy(100);
// 原点情報初期化
L6470_data_transfer(0xd8,0,0);
L6470_wait_not_busy(800);
}
// 初期設定
void L6470_set_parameter(){
L6470_data_transfer(0x05,2,0x0e);
L6470_data_transfer(0x06,2,0x0e);
L6470_data_transfer(0x07,2,0x0e);
L6470_data_transfer(0x08,2,0x01);
L6470_data_transfer(0x15,2,0x3ff);
L6470_data_transfer(0x09,1,0x50);
L6470_data_transfer(0x0a,1,0x50);
L6470_data_transfer(0x0b,1,0x50);
L6470_data_transfer(0x0c,1,0x50);
L6470_data_transfer(0x16,1,0x03);
}
// L6470リセット
void L6470_rst_device(){
L6470_data_send_u(0x00); //nop命令
L6470_data_send_u(0x00);
L6470_data_send_u(0x00);
L6470_data_send_u(0x00);
L6470_data_send_u(0xc0);
}
// L6470送信データ加工
void L6470_data_transfer(int add,int bytes,long val){
int data[3];
L6470_data_send(add);
for(int i=0;i<=bytes-1;i++){
data[i] = val & 0xff;
val = val >> 8;
}
if(bytes==3){
L6470_data_send(data[2]);
}
if(bytes>=2){
L6470_data_send(data[1]);
}
if(bytes>=1){
L6470_data_send(data[0]);
}
}
// L6470データ送信(BUSY解除待機)
void L6470_data_send(unsigned char add_or_val){
while(!digitalRead(PIN_BUSY)){}
digitalWrite(PIN_SPI_SS, LOW); // ~SSイネーブル。
SPI.transfer(add_or_val); // アドレスもしくはデータ送信。
Serial.println(add_or_val,HEX);
digitalWrite(PIN_SPI_SS, HIGH); // ~SSディスエーブル。
}
// L6470データ送信(BUSY状態関係なし)
void L6470_data_send_u(unsigned char add_or_val){
digitalWrite(PIN_SPI_SS, LOW); // ~SSイネーブル。
SPI.transfer(add_or_val); // アドレスもしくはデータ送信。
digitalWrite(PIN_SPI_SS, HIGH); // ~SSディスエーブル。
}
// BUSY解除待機
void L6470_wait_not_busy(long time){
// BUSY解除待機
while(!digitalRead(PIN_BUSY)){
chk_sw_input();
}
delay_checking_sw_input( time );
}
// 指定時間待機
void delay_checking_sw_input(unsigned long time ){
// BUSY解除待機
unsigned long tm_bgn = millis();
unsigned long tm_now = millis();
unsigned long tm_dif = tm_now - tm_bgn ;
while( tm_dif < time ){
chk_sw_input();
tm_now = millis();
tm_dif = tm_now - tm_bgn ;
}
}
//SW入力確認・LED出力
void chk_sw_input(){
val_bsy = digitalRead(PIN_BUSY);
val_org = !digitalRead(PIN_LMT_ORG);
val_end = !digitalRead(PIN_LMT_END);
int val_tmp = !digitalRead(TMP_2) | !digitalRead(TMP_3) | !digitalRead(TMP_4) | !digitalRead(TMP_5);
// LEDのピンを読み取った値に変更
digitalWrite(PIN_DRV_LED, val_bsy);
// LEDのピンを読み取った値に変更
digitalWrite(PIN_LMT_LED, val_org | val_end | val_tmp);
}
4.まとめ
RS232C変換の必要性は理解できていませんが、とりあえず通信出来ている様です。15m離すことが出来るので、機器間の距離を心配することはなくなりそうです。