読者です 読者をやめる 読者になる 読者になる

女子力発電所(仮題)

ブログの中身も人生もぶれる日々

ArduinoとPCのシリアル通信でデジタル出力を制御する

ArduinoのD2~D9の8つを使って、デジタル出力をします。


出力パターンが決められていたり、即時性がそれほど求められない場合はもっと違う手法が有るのですが、出力に数ミリ秒の分解能が必要だったりすることがある場合に使えるのではないかと思います。


ソースは汚いですが、まずArduinoのスケッチから。MsTimer2をインストールしてください。

#include <MsTimer2.h>

volatile byte outdata = B00000000;
volatile unsigned int count = 0;
volatile boolean dataoutput = false; //デジタル出力中
volatile int ptr = 0; //PCからの電文解析:0は0x40待ち,nはnByte目読み中
volatile boolean nowstop = true; //最初の電文待ちかどうか
volatile int TXRXPacketDelta = 0; //電文バッファーがどれだけあるか
volatile int bufcont = 0; //電文バッファーのコントロール用パラメーター

void samplingOUT(){
	byte buf1,buf2;

	if(dataoutput){
		count --;
		buf1 = (outdata & B00111111)<<2; //PORTD;
		buf2 = (outdata & B11000000)>>6; //PORTB
	}else{
		buf1 = B00000000;
		buf2 = B00000000;
	}

	PORTD = (PORTD & B00000011) | (buf1 & B11111100);
	PORTB = (PORTB & B11111100) | (buf2 & B00000011);
  
	if(count == 0){
		dataoutput = false;
	}

}

void setup(){

	for(int i=2;i<=9;i++){
		pinMode(i,OUTPUT);
		digitalWrite(i,LOW);
	}

	Serial.begin(19200);
//Arduinoのシリアルはすぐには初期化できないみたいなので…
	delay(5000);

//分解能は10ミリ秒(10ミリ秒以下のパルスは出せない)
	MsTimer2::set(10,samplingOUT);
 	MsTimer2::start();
}

void loop(){

	byte sdata;

	int incoming = Serial.available();

	if(dataoutput == false && incoming >0){
		sdata = Serial.read();
		if(denbun_parse(sdata) == -1){
			bufcont = 1;
		}
	}

	switch(bufcont){
		case 1:
		case 3:
			if(TXRXPacketDelta >=10){
				bufcont = 2;
			}else{
				Serial.write((byte)incoming);
				TXRXPacketDelta ++;
			}
			break;

		case 2:
			if(TXRXPacketDelta <=5){
				bufcont = 3;
			}
			break;

		default:
			break;
	}

}
  

int denbun_parse(byte sd){
	int ret=0;

	switch(ptr){
		case 0:
			if(sd == 0x40){
				ptr = 1;
			}
			return 0;

		case 1:
			count = ((unsigned int)(sd))*256;
			ptr = 2;
			return 0;

		case 2:
			count = count + (unsigned int)sd;
			ptr = 3;
			return 0;

		case 3:
			outdata = sd;
			ptr = 4;
			return 0;

		case 4:
			if(sd == 0x80 && count != 0){
				if(nowstop == true){
					nowstop = false;
					ret = -1;
				}else{
					dataoutput = true;
					ret = 1;
					TXRXPacketDelta --;
				}
		   }
			ptr = 0;
			return ret;
	}
}

PC側からArduinoのシリアルポートへは、以下のような電文のシーケンスが必要になります。


(1)PC側が準備できたら 0x40 0x00 0x00 0x00 0x80の5バイトをシリアルに送信する(実は頭の0x40と0x80以外は何でもいい)。


(2)PC側はシリアルポートから1バイトの電文を受けるたびに、今後出力したい順番通りに以下の電文を出す。


0x40(固定) (2バイトで時間を表す) (ポートの出力パターンを1バイトで) 0x80(固定)


 時間はビッグエンディアンで、実際に出したい状態の時間の10ミリ秒で割った数です。
 また、ポートのパターンは下位ビットがD2→最上位ビットがD9になります。


 (例1) 100ミリ秒間、全ポート出力 → 0x40 0x00 0x0A 0xFF 0x80
(例2) 1分間(60000ミリ秒=6000×10ミリ秒)、D2,D4,D6,D8ポートのみON → 0x40 0x17 0x70 0x55 0x80


 ただし、10分以上連続したパルス(要するに時間のところが0xFF 0xFF … 655350ミリ秒)を越す場合は電文を分ける必要があります。


テストしたPC側のPythonのソースです。


Windows7環境下でserialが必要になります。("COM5"は環境に応じて変更してください)


ArduinoのD2出力にLEDを接続すると、1秒間ごとにON/OFFを繰り返し、D3は2秒毎、D4は4秒ごと…となります。

import serial
from time import sleep
from struct import pack,unpack

s = serial.Serial("COM5",baudrate=19200,parity='E',timeout=0)
count = 0;

sleep(5)
s.flushInput()
s.flushOutput()
sleep(5)
s.write(pack('5B',0x40,0x00,0x00,0x00,0x80))

while True:
	r = s.inWaiting()
	if r != 0:
		p = s.read()
		m = count % 256
		head = pack('5B',0x40,0x00,0x64,m,0x80)
		s.write(head)
		print "Pulse Output Pattun %d Rest Buffer(Arduino) %d Incoming Buffer(Arduino to PC) %d" % (m,ord(p),r)
		count = count + 1

SAKURA BOARDを手に入れました

ルネサスのMPU、RX63Nを使ったマイコンボード、SAKURA BOARDをとある人から譲り受けました。

http://sakuraboard.net/

 

ここにもあるとおり、Arduinoのスケッチの概念やシールドの互換がありそうです。

http://tool-cloud.renesas.com/Renesas/ref/gr_reference_j.html

 

パッケージです。日本を意識しています。(Arduinoはもっとイタリアを意識して欲しかったな…留めてあるシールくらいだよね…)

f:id:itamae:20130211115548j:plain

 

Arduino互換のシールドが使えそうですが、Arduino UNOにあるIOREF,ResetピンはSAKURA BOARDにはありません。また、Arduino MEGA程ではありませんが、別途IOポートをつなげられそうです。

Ethernet(RJ-45端子)は標準で、USB端子はミニBタイプ(←若干注意)です。

裏側にはMicroSDカード用のソケットもあります。

茶色いボタン(SW1)はリセットスイッチですが、PCにストレージとしてみなす為に必要なボタンになります。

MPUArduino UNOがATmega328(16MHz)ですが、SAKURA BOARDはRX63N(96MHz)と高速です。

f:id:itamae:20130211141012j:plain

 

横から見ると分かるのですが、RJ-45端子の高さが有るので、シールドによってはRJ-45に干渉するかもしれませんね。

f:id:itamae:20130211141041j:plain

 

これから色々いじってみますが、EthernetやMicroSDを使って面白そうなことができそうな感じがします。

Google Driveスプレッドシートの特定のシートの最初のカラム以外を消す(3)

(2)からの続き
  • 確認と使えるようにするには

このスクリプトがマトモに動くかどうかは画面の以下のところにある「実行」ボタンを押してください。

f:id:itamae:20130128010118p:plain

エラーが出ない場合は、スプレッドシート自体を見に行ってみてください。

こんな(↓)感じになっているはずです。

f:id:itamae:20130128010302p:plain

 

マトモに動いていると思うので、あとは特定のURLにアクセスすると勝手に消してくれるようにしましょう。

 

まずは、「ファイル」→「バージョン管理」を選んでください。試験運用中ですがキニシナイ!

f:id:itamae:20130128010727p:plain

すると以下のような画面が出ますので、バージョン名を数字で入力してください。

f:id:itamae:20130128010908p:plain

OKボタンを押すと以下のようになり、左側の「バージョン」の番号を覚えておいてください。最初は「1」になるかと思います。

f:id:itamae:20130128011216p:plain

OKを押して、次は「公開」→「ウエブアプリケーションとして導入」を選択してください。

f:id:itamae:20130128011455p:plain

以下の画面が出たら、先程のバージョン名とアプリケーションの実行する権限を選択して(通常なら、下の画面のようだと思います)導入ボタンを押してください。

f:id:itamae:20130128011650p:plain

 

しばらくすると非常に重要な以下の画面が出ます。

f:id:itamae:20130128011929p:plain

この「現在のウエブアプリケーションのURL」以下にあるhttpsから始まる行をコピーしてください。

 

以降、このコピーしたURLをアクセスするたび、スプレッドシートがクリアされます。

アドレスバーにそのまま入れても良いんですが、コマンドラインとかで

/usr/bin/chromium-browser https://script.google.com/macros/s/(ほにゃらら)

みたいなのを実行させても良いのではないかと思います。

 

 

追伸

正直超誰得なんだろうね、この記事…。

Google Driveスプレッドシートの特定のシートの最初のカラム以外を消す(2)

(1)からの続き

  • スクリプトを書くよ

スクリプトの仕様とかは英語で書かれています。

https://developers.google.com/apps-script/overview

Javascriptチックなので、腕に覚えのある人はさほど難しくないと思います。
さて、先程のエディタの画面に以下を入力していきます。

function myFunction() {

//SheetのIDには後ほど説明するスプレッドシートのKeyを入れる。
//このスプレッドシートのタブ「data」にアクセスする場合
  var sheetid = SpreadsheetApp.openById("SheetのID").getSheetByName("data");

// 行(縦方向)の最終行番号を取得
  lastrow = sheetid.getLastRow();

//列(横方向)の最終番号を取得
  lastcor = sheetid.getLastColumn();

//2行目から最後までクリアします。
  sheetid.getRange(2,1,lastrow,lastcor).clear();

}

// doGetという関数がアクセス時に呼ばれます
function doGet(){

  myFunction();
  return UiApp.createApplication();
}

で、このスクリプトの"SheetのID"ってのは何かというとですね、スプレットシート自体のURLを見ていただくと以下のような感じになっていると思います。
f:id:itamae:20130128004019p:plain
https://docs.google.com/spreadsheet/ccc?key=
のあとの文字で、「#」より前の文字が、そのSheetのIDとなります。この文字をコピペしておいてください。

なお、入力中は以下のようにVisual Studioで言うところのIntellisense的なことが出ますので安心ですね!
f:id:itamae:20130128004353p:plain

スクリプトを入力が済んだら保存しましょう。
スクリプト自体のファイル名と、複数のスクリプトをまとめることができるプロジェクトに名前をつけましょう。

(スクリプトの名称変更)
f:id:itamae:20130128004825p:plain

(プロジェクト名を付ける)
「ファイル」の「名前を付けて保存」で以下の画面が出ますので、プロジェクト名(Google Driveに表示される名称)を入力して、「OK」を押しておいてください。
f:id:itamae:20130128005205p:plain

後でGoogle Driveのトップ画面を見るとこんな感じになるはずです。
f:id:itamae:20130128005331p:plain

(3)へ続く

Google Driveスプレッドシートの特定のシートの最初のカラム以外を消す(1)

GoogleDrive使ってますか?

私は市場が開いている日は、日経先物の素データをスプレッドシートにぶち込んで、出先とかでも色々いじって楽しんでいるのですが。

そんなわけで、スプレッドシートを毎日データ更新するのですが、特定のシートを消すけど、最初のカラム(データの項目名)を残して全部消すことが要求されます。

みんな、そんな事で困ってるよね?(多分困ってない)

ということで、GoogleDrive内のコンテンツをいじる為にある、Google Apps Scriptの使い方とかのメモを。

 

  • まずはデータを。

f:id:itamae:20130127235713p:plain

ブラウザーでGoogleDriveを開いたあと、Google Drive内にこんな(↑)タイトルのスプレッドシートが有るとします。

中身はこんな感じ。

f:id:itamae:20130127235815p:plain

先程の画面の「作成」ボタンを押すと作成できるコンテンツの一覧が出てきますが、マニア用なので(意味不明)、もっと見るに移行すると、「スクリプト」というのが出てきますので、ここを選択してください(下の画面)。

f:id:itamae:20130128000123p:plain

その後以下の画面が出ますので、左上の「空のプロジェクト」を選んで下さい

f:id:itamae:20130128001206p:plain

するとエディタな感じのするページが出てきます。

f:id:itamae:20130128000422p:plain

ここにスクリプトを書いていきます。

 

(2)へ続く

ご挨拶をQA方式で

はじめまして!id:itamaeです。

Q1.このブログのタイトル(女子力発電所(仮題))の意味は?

A1.ある記事を読んでいたら、「原子力発電所」の「原」の後で改行があって、「もし、これが女子力発電所だったら、くだんねーな」と思ったからです。おそらくいずれタイトルを変えると思います。

 

Q2.そもそもあなた、誰ですか?

A2.twitterのプロフィールが詳しそうなので、見てみてください。

https://twitter.com/itamae

 

Q3.ブログの内容は?

A3.現在どうするか決めかねていますが、おそらくはマイコンネタ(Arduinoあたりから攻める予定)か、株の自動売買システムを検討する記事かなと(売買ロジックは別)。こっちはtwitterと違ってマジメに取り組もうと思っています。