ラベル UART の投稿を表示しています。 すべての投稿を表示
ラベル UART の投稿を表示しています。 すべての投稿を表示

2014年7月31日

ATtiny85で赤外線シリアル通信

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回前々回の続き。
赤外線LED(OSI5FU5111C-40)とフォトトランジスタ(L-51ROPT1D1)を使ったシリアル通信をATtiny85で実現させます。
さらに、このATtiny85とArduinoをI2Cで接続し、I2C-赤外線通信コンバーター化します。

構成はこんな感じ。

ATtiny85の各ピンは以下の通り。

pin1 - RESET
pin2 - Serial RX (from フォトトランジスタ)
pin3 - Serial TX (to 赤外線LED)
pin4 - GND
pin5 - I2C SDA (Arduino A4)
pin7 - I2C SCL (Arduino A5)
pin6 - not used(D1)
pin8 - VCC

pin6が空いているので、更に何か追加することもできますが、今回は未使用。

ATtiny85をArduinoとして扱う方法は「Programming an ATtiny w/ Arduino 1.0」 を参考にしました。
書き込みはaitendoで購入し、以前の記事でファームウェアのアップデートを行ったUSBasp-Bを使用。
ATtiny85は内蔵RC 8MHz駆動です。

プログラムは以下の様な感じ。(たぶんもっとキレイに書けるはず...)

#include <SoftwareSerial.h>
#include "TinyWireS.h"

#define I2C_SLAVE_ADDR  13
#define IR_RX 3 // pin2
#define IR_TX 4 // pin3

SoftwareSerial irPort(IR_RX, IR_TX, false);

void receiveEvent(uint8_t a) {
  int i = 0;
  char c;
  char buf[100];
  if (TinyWireS.available()) {
    while(TinyWireS.available()){
      c = TinyWireS.receive();
      buf[i] = c;
      i++;
      buf[i] = '\0';
      delay(2);
    }
    irPort.write(buf);
  }
}

void requestEvent() {
  if(irPort.available()){
    char c = irPort.read();
    if(c!=255)
      TinyWireS.send(c);
  }
}

void setup() {
  TinyWireS.begin(I2C_SLAVE_ADDR);
  irPort.begin(1200);

  TinyWireS.onReceive(receiveEvent);
  TinyWireS.onRequest(requestEvent);
}

void loop() {

}

Arduino UNO側はこんな感じ。

#include <Wire.h>

void setup(){
  Serial.begin(9600);
  Wire.begin();
}

void loop(){
  if(Serial.available()){
    int i = 0;
    char c;
    char buf[100];
    while(Serial.available()){
      c = Serial.read();
      buf[i] = c;
      i++;
      buf[i] = '\0';
      delay(2);
    }
    Wire.beginTransmission(0); //broadcast
    Wire.write(buf);
    Wire.endTransmission();
  }

  Wire.requestFrom(13,1);
  if(Wire.available()){
    byte b = Wire.read();
    if(b!=0xff && b!=0x0a && b!=0x00)
      Serial.write(b);
  }
}

これで、一番上の写真のように向かい合わせにして赤外線通信ができます。
UNO側のコードでbroadcastにしているのは訳があって、このあとATtiny85を複数個ぶら下げる予定。

2014年6月1日

続・赤外線LEDとフォトトランジスタでシリアル通信

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回の続き。
赤外線LED(OSI5FU5111C-40)とフォトトランジスタ(L-51ROPT1D1)を使ったシリアル通信。
今回は、送受信×2で双方向(全二重)通信を実現させます。

構成は...
PC <---Serial---> Arduino <---赤外線---> Arduino <---Serial---> PC
こんな感じ。

前回のものを一体化して、以下のようにする。

これを2個用意し、互い違いになるように向かい合わせて配置。


プログラムは以下の通り。

#include <SoftwareSerial.h>

SoftwareSerial irPort(10, 11, false);

void setup() {
  irPort.begin(1200);
  Serial.begin(9600);
}

void loop() {
  int i = 0;
  char c;
  char buf[100];
  if(Serial.available()){
    while(Serial.available()){
      c = Serial.read();
      buf[i] = c;
      i++;
      buf[i] = '\0';
      delay(2);
    }
    irPort.print(buf);
  }

  if (irPort.available())
    Serial.write(irPort.read());
}

最初はSerialから赤外線へ渡す部分を
if (Serial.available()) {
    irPort.write(Serial.read());
}
こんな感じにしていたけど、これだとループの早さにSerial.readが追いつかないっぽい。
abcdefgと送るとabcgになる等、データが途中で抜けたりするので一旦バッファに全部溜めてからprintするようにしました。
ちなみに、上記コード中のdelay(2)を取ると、途中が抜けたり最初の3文字くらいしか取れない現象が発生するので、やはりSerial.readが原因の模様。
当初のコードのirPort.writeの前行にdelayを入れるのも試してみたが、10msくらいにしないとダメだったので、バッファに溜めた方が早いかなと。

上記写真のような配置で距離を離して双方同時に送信すると、互いが干渉して文字抜けや化けが発生するので、実際は間に遮蔽を入れるなどの工夫が必要。
試しに紙を1枚入れてみたら安定して通信できました。

2014年5月31日

赤外線LEDとフォトトランジスタでシリアル通信

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

久々のArduinoネタ。
赤外線LED(OSI5FU5111C-40)とフォトトランジスタ(L-51ROPT1D1)を使ってシリアル通信をする。
最終的にATtiny85に載せる計画なので、SerialではなくSoftwareSerialを使っています。

送信側はこんな感じ。
普通のLEDと同様に抵抗1本を入れる。


受信側はこんな感じ。
トランジスタ(2SC1815)を入れてD10に接続。


これを向かい合わせにして、配置する。


プログラムは以下のような感じ。
送信側
#include <SoftwareSerial.h>

SoftwareSerial sender(10, 11);

void setup() {
  sender.begin(1200);
}

void loop() {
  sender.println("Hello World!");
  delay(1000); 
  sender.println("1234567890");
  delay(1000);
  sender.println("abcdefghijklmnopqrstuvwxyz");
  delay(1000); 
}

受信側
#include <SoftwareSerial.h>

SoftwareSerial receiver(10, 11, false);

void setup() {
  receiver.begin(1200);
  Serial.begin(9600);
}

void loop() {
  if (receiver.available()) {
    Serial.write(receiver.read());
  }
}

送信側のプログラムは、「Hello World!」→「1234567890」→「a〜z」を1s毎に出力、受信側は赤外線で受け取ったデータをSerialにそのままフォワーディングするような感じ。
仕組み的には独自のプロトコルではなく、Serial(SoftwareSerial)を使っているので特に複雑な訳でもなくサクッと使えるのが利点。

環境にもよると思いますが、この構成だと約20cmくらいまで離しても通信できました。
通信距離を伸ばすには赤外線LEDの球数を増やす、電圧を上げる(もちろん高出力タイプに置換した上で)等で出力を強くする必要あります。

次の記事では送受信×2で双方向(全二重)を実現させます。

2013年6月30日

PICでBluetooth SPP - UARTコンバータ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

BluetoothのSPPが使えるモジュール、技適マーク付きの物を買うと5000円以上したりします。
これを市販のUSBドングル型Bluetoothモジュールを使ってなんとかしようというネタ。

使うのはPIC24FJ64GB002というUSB OTGが使えるマイコンで、今のところ買えるのはRSやDigiKeyを除いて共立電子のみ。


回路はこんな感じでOK
USBコネクタ部分の配線がよく分からない順番になってますが、実際は
1 - VCC
2 - D- (図の茶色線)
3 - D+ (図の黄色線)
4 - GND
という感じでAメスコネクタと配線してください。

電圧は3.3V。
PicKit3から電源供給する際はプロジェクトのプロパティから電源供給をONに。(MPLAB X)
Arduinoのシールド化する際は3.3Vから引きます。
(本当はあんまり良くないけど)RX/TXは直でArduinoと接続しても問題なし。

実際に使う場合は、右上のFTDI breakooutが繋がってるRX、TX、GNDをUART通信したいデバイスに接続します。


Arduinoと接続してAndroidとSPPで通信している様子。
ここでは、ONと送るとArduinoの13番pinのLEDが点灯、OFFと送ると消灯というスケッチをArudinoに書き込んでいます。

PIC側のプログラムは、hrdakinori氏のPIC24F_btstackをベースに、UARTからの受信をBuetooth SPPに渡すコードを追加すればOKです。

具体的にはこんな感じで、まずbt_spp.cのbt_spp_recive_callbackを以下の様な感じに。

int bt_spp_recive_callback(uint16_t channel, uint8_t *packet, uint16_t size)
{
 packet[size] = 0;
        
        //SPP to UART
        UART2PrintString(packet);
        
 return 0;
}

更に、main.cのsw_processを以下の様な感じに。

static int sw_process(struct data_source *ds)
{
    if(IFS1bits.U2RXIF == 1){
 char text[100]={0};
        int i = 0;
        char c = 0;

        while(1){
            while(U2STAbits.URXDA) {
                c = U2RXREG;
                text[i] = c;
                i++;
            }
            if (c == '\n') break;
            else if(c == 0) break; // if UART no Connect, break while(1)
        }
        text[i] = 0; //

        //UART2PrintString(text); //debug and callback

        //Bluetooth Send
        bt_spp_send((uint8_t*)text,strlen(text));

        IFS1bits.U2RXIF = 0;

 if ( U2STAbits.OERR) {
  U2STAbits.OERR = 0;
 }
    }
 return 0;
}

あと、コンパイル時にundefined reference to packet_handlerが出るので、btstackのhci.c内のstatic void packet_handlerをvoid packet_handlerに変更します。

PICとのシリアル通信は57600bpsで、Bluetooth側は特に制約は無い(はず)。


こんな感じでSwitch Scienceさんのバニラシールドに載せてしまえば、Arduino UNOやMEGAのシールドとして普通に使えます。