CD4052を使ってシリアル通信を拡張する


前回、8chマルチプレクサーのCD4051を紹介しました。
タッチセンサーとは全く関係ありませんが、今回は4chマルチプレクサーのCD4052を紹介し ます。
9番ピン、10番ピンの値で、0から3までのチャネルを切り替えることができますが、
同時に2本のライン(XとY)が切り替わります。

RaspberryにはUARTピン(GPOI14と15)があるのでシリアル通信を行う事ができますが、
1組しかUARTがないので、同時に複数のデバイスとシリアル通信を行う事ができません。
そこで、CD4052を使って、同時に複数のデバイスとシリアル通信を行う方法を紹介します。

但し、通信できるのは
@Raspberryからデバイスに通信
AデバイスからRaspberryに応答
のパターンだけです。



最初にraspi-configを使ってシリアルからのログインを無効にします。



また、Jessieではこれだけではダメなようで、こ ちらで 紹介されているようにサービスを止める必要があります。

今回、通信相手にはOrangePiを使いました。
ワイヤーリングは以下のようになります。
OrangePiのパーツ図がなかったのでRaspberryのパーツ図で代用していますが、下の2台が通信相手のOrangePiです。
CD4052のチャンネル0とチャネル1を使います。



【RaspberryPi側】

Raspberry側のコードは以下のようになります。

//
// Serial Send Program
//
// cc -o serialS serialS.c -lwiringPi
//
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>

// Define Pin
#define BCD     0  // GPIO 0
#define INH     3  // GPIO 3
#define DEBUG   0

int readSerial(int fd, char * buff, int blen, int timeout) {
  unsigned long endTime;
  int ch;
  int pos = 0;

if(DEBUG)printf("millis=%d\n",millis());
  endTime = millis () + timeout;
if(DEBUG)printf("endTime=%d\n",endTime);
  buff[pos] = 0;

  while (1) {
    if (millis () > endTime) return -1;
    if (serialDataAvail (fd)) {
      ch = serialGetchar (fd);
if(DEBUG)printf (" -> %02x\n", ch);
      if (ch == 0x0d) {

      } else if (ch == 0x0a) {
        return pos;
      } else {
        if (pos < blen) buff[pos++] = ch;
        if (pos < blen) buff[pos] = 0;
      }
    } // end if
  } // end while
}

int SetChannel(int uart)
{
  unsigned int mask;
  int i;

  digitalWrite(INH,1);
  for(i=0;i<2;i++) {
    mask=(1 << i);
    if (uart & mask) {
      digitalWrite(BCD+i,1);
if(DEBUG)printf("%d=ON\n",i);
    } else {
      digitalWrite(BCD+i,0);
if(DEBUG)printf("%d=OFF\n",i);
    }
  }
  digitalWrite(INH,0);
  usleep(1);
//  sleep(1);
}


int main (int argc, char **argv) {
  int fd;
  int len;
  int uart;
  int c;
  char buff[64];
  char device[32];

  strcpy(device,"/dev/ttyAMA0");
  if (argc == 2) strcpy(device,argv[1]);
  printf("device=%s\n",device);

//  if ((fd = serialOpen ("/dev/ttyAMA0", 115200)) < 0) {
  if ((fd = serialOpen (device, 115200)) < 0) {
    printf ("Unable to open serial device: %s\n", strerror (errno)) ;
    return 1 ;
  }

  if (wiringPiSetup () == -1) {
    printf ("Unable to start wiringPi: %s\n", strerror (errno)) ;
    return 1 ;
  }
  pinMode(BCD,OUTPUT);
  pinMode(BCD+1,OUTPUT);
  pinMode(INH,OUTPUT);

//Set CD4052
  printf("enter CD4052 Channnel=");
  scanf("%d",&uart);
  SetChannel(uart);
  printf("CD4052 Channnel=%d\n",uart);

//Send data
  serialPrintf (fd,"Hello Channel=%d!!\n",uart);
//Receive data
  len=readSerial(fd, buff, sizeof(buff),10000);
  printf("readSerial len=%d data=[%s]\n",len,buff);
}


【OrangePi側】

OrangePi側のコードは以下のようになります。
受信した文字列を表示して、自分のホスト名を返すだけです。
起動時の引数でUARTのデバイスファイルを指定します。
// Serial Receive Program
//
// cc -o serialR serialR.c -lwiringPi
//
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>

#define    DEBUG    0

int readSerial(int fd, char * buff, int blen, int timeout) {
  unsigned long endTime;
  int ch;
  int pos = 0;

if(DEBUG)printf("millis=%d\n",millis());
  endTime = millis () + timeout;
if(DEBUG)printf("endTime=%d\n",endTime);
  buff[pos] = 0;

  while (1) {
    if (millis () > endTime) return -1;
    if (serialDataAvail (fd)) {
      ch = serialGetchar (fd);
if(DEBUG)printf (" -> %02x\n", ch);
      if (ch == 0x0d) {

      } else if (ch == 0x0a) {
        return pos;
      } else {
        if (pos < blen) buff[pos++] = ch;
        if (pos < blen) buff[pos] = 0;
      }
    } // end if
  } // end while
}


int main (int argc, char **argv) {
  int fd;
  int len;
  char buff[64];
  char device[32];
  char hostname[128];

  strcpy(device,"/dev/ttyAMA0");
  if (argc == 2) strcpy(device,argv[1]);

//  if ((fd = serialOpen ("/dev/ttyAMA0", 115200)) < 0) {
  if ((fd = serialOpen (device, 115200)) < 0) {
    printf ("Unable to open serial device: %s\n", strerror (errno)) ;
    return 1 ;
  }

  if (wiringPiSetup () == -1) {
    printf ("Unable to start wiringPi: %s\n", strerror (errno)) ;
    return 1 ;
  }
  printf("wiringPiSetup\n");
  gethostname(hostname, sizeof(hostname));
  printf("hostname=%s\n", hostname);


  while(1) {
//  Receive data
    len=readSerial(fd, buff, sizeof(buff),10000);
    if (len != -1) {
      printf("readSerial data=[%s]\n",buff);
//    Send data
//      serialPrintf (fd,"You are Welcome!!\n");
      serialPrintf (fd,"%s\n",hostname);
    }
  }
}

OrangePi側のコードを実行したのち、Raspberry側のコードを実行すると以下の様になります。
きちんと相手のホスト名が応答されています。


CD4052のチャネル0を使うOrangePi側には以下のように表示されます。


チャネル1のOrangePi側には以下のように表示されます。


今回紹介したのは
@Raspberryからデバイスに通信
AデバイスからRaspberryに応答
のパターンですが、逆向きの
@デバイスからRaspberryに通信
ARaspberryからデバイスに応答
を行うには、以下のような専用のチップを使用する必要がありますが、1000円以上しますね。



OrangePiシリーズなら同時に3つのUARTが使えるので、このような場合には、こちらをお勧めします。