通信はほかのディバイスとのデータの送受信になります。
パソコンなどとの通信にはシリアル通信,近くにある機械との通信はI2C・SPIがあります。電波による通信はBluetooth・wifiがあります。赤外線や超音波による通信もあります。
通信ということはデータの送受信なので入出力の全てが通信になります。
ここではシリアル通信について学んでいきたいと思います。
パソコンと通信 送信
せっかくパソコンとつながっているのですからパソコンと通信できるようにしたいと思います。しかも用意する物は何も有りません。パソコンとはプログラムの転送のため,すでにUSBケーブルでつながれています。
Arduinoが何を言ってくるか見るためにシリアルモニタを使います。
シリアルモニタ
serial01
1
2
3
4
5
6
7
8
//初期設定
void setup() {
Serial.begin(9600);//serial初期化
}
//繰り返し
void loop() {
Serial.write("Hello");
}
スケッチ
HelloHelloHello
送信
シリアル通信は初期設定のvoid setup(){の3行目のSerial .begin(9600);で始めることができます。
void loop(){の中でSerial.write()の()内に通信したい文字を""でくくって入れます。
改行
しかし横に流れてしまいます。そこでwriteの代わりにprintlnとします。すると改行してきれいに表示されます。writeとprintはあまり変わらない様ですが,lnはprintにしか付けることはできません。
送信
serial02
//初期設定
void setup() {
Serial.begin(9600);//serial初期化
}
//繰り返し
void loop() {
Serial.println("Hello");
}
Hello
Hello
Hello
改行されて見やすくなりました。
ただし,ものすごい速さで「Hello」を送信してくるので,それこそ目にも止まりません。
writeとprintの違い
lnが使えるのはprint文です。普通はprintを使います。Serial.write( )はByteを扱います。
パソコンと通信 受信
serial03
1
2
3
4
5
6
7
8
9
10
//初期設定
void setup() {
Serial.begin(9600);//serial初期化
}
//繰り返し
void loop() {
byte m;
m=Serial.read();
if(m!=255){Serial.println(m);}
}
通信を使えるようにするのは送信の時と同じです。
受信ですから何が送られてくるのかわかりません。そこで,送られてきたものを受け入れる容器を用意しましょう。一応文字だということにします。1文字ならば1byteの容量でいいと思います。7行目でmという変数をbyteの仕様にします。8行目でmにシリアル通信で得た値を入れます。データの通信は数字で行われます。何もしなければmは255になっています。ですから,mが255でない時だけmを返せばいいのです。
if文(もし~ならば)!は無いまたは違うの意味
最後の行は,もしmが255でない時は{}内を実行せよということです(マルチステートメントになっています)。
mを送信します。ただし,mそのものではなくてmの数字です。
たった10行のスケッチですがプログラムらしくなってきました。
行番号があると説明がわかりやすくなります。
ファイル→環境設定→行番号を表示するとします。
文字列の受信
一文字を受信することは簡単にできますが,文字列の受信には工夫が必要です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//宣言
//初期設定
void setup() {
Serial.begin(9600);//serial初期化
}
//繰り返し
void loop() {
int i=0;//文字数をカウント
char str[100]="";//文字を記憶する変数,初期化
while(Serial.available()){//読み込む文字があれば
str[i]=Serial.read();//i番目の文字として入力
delay(10);//通信のための時間
i++;}
if(i!=0){
Serial.println(str);}//送信
}
Serial.available( );でバッファに文字があることを確かめ,存在する場合char str[ ]="";で確保した変数に入力していきます。32文字までは読み込めます。
String str;
str=Serial.readString();は少し遅いのですが簡単です。
11行目のchar str[100]="";の=""を省略すると文字が残ってしまいます。
14行目のdelay(10);を書かないと文字の読み込みに失敗してしまいます。"";
Hexデータを配列にする
char_num_00_03
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void setup(){//初期化
Serial.begin(9600);
Serial.println("Ready");
}
void loop() {//繰り返し
int hex=0xaa;//Hexデータ
int bin[]={0,0,0,0,0,0,0,0};//配列
for(int i;i<8;i++){//変換
int a=hex/2;
bin[7-i]=(hex-a*2);
hex=a;
}
for(int i;i<8;i++){//通信・表示
Serial.print(bin[i]);
}Serial.println();
delay(1000);
}
Hexデータを0,1の配列に格納し直します。
RaspberryPiの場合
I2C通信
I2C接続で動作するLCD
2017年7月1日
比較的近い距離にあるディバイスとの通信に使われる2線式(2線+VCC+アース)通信です。
ACM1602NI
I2C 16×2 LCDキャラクタディスプレイ
I2Cアドレス
I2Cアドレスは0x50です。データシート7.0.3の2行目から3行目に
Only one 7-bit slave addresses (1010000) is reserved for the LCM 0x 5 0
と書いてあります。
Arduinoとの接続
VSSはGND,VDDは3.3Vまたは5Vです。
BL+とBL-でバックライトLEDを点灯します。
VOはコントラスト調整です。
SCLは1番pin,SDAは2番pinへプルアップして接続します。
コントラストは液晶側にVRを付けてもいいと思います。プルアップはArduino側ですね。RTCには10Kのプルアップが付いているので必要ありません。
サブルーチン
I2C_LCD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <Wire.h>//I2C接続
void setup() {//初期設定部
}
void loop() {//繰り返し部
}
//関数・サブルーチン
void writeCmd(byte cmd){//コマンド送信
Wire.beginTransmission(0x50);
Wire.write(0x00);//第1BYTE
Wire.write(cmd); //第2BYTE
Wire.endTransmission();//ストップ
}
void writeData(uint8_t dat){//データ送信
Wire.beginTransmission(0x50);
Wire.write(0x80);// 第1BYTE
Wire.write(dat); // 第2BYTE
Wire.endTransmission();//ストップ
}
これら2つのサブルーチンを書いておけばほとんどの動作をさせることができます
コマンド
インストラクション
インストラクションコード
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0
0
0
0
0
0
0
0
0
1
カーソル0,0
RAM読み込み
RAM書き込み
フラグ読み込み
DDRAMアドレス
CGRAMアドレス
機能設定
カーソル 表示
表示On,Off
モードセット
表示初期化
0
0
0
0
0
0
0
0
1
-
0
0
0
0
0
0
0
1
I/D
S
↑ ↑
↑拡張表示
カーソル移動方向
1インクリメント
0デクリメント
0
0
0
0
0
0
1
D
C
B
↑ ↑ ↑
↑ ↑ ブリンク
↑ カーソル表示
ディスプレイOn
0
0
0
0
0
1
S/C
R/L
-
-
↑ ↑
↑ ↑
↑ 移動方向
カーソル移動
0
0
0
0
1
DL
N
F
-
-
↑ ↑ ↑
↑ ↑5×10,5×8dots
↑ ディスプレイ行数
1,8bit 0,4bitデータ長
0
0
0
1
ac5
ac4
ac3
ac2
ac1
ac0
0
0
1
ac6
ac5
ac4
ac3
ac2
ac1
ac0
0
1
BF
ac6
ac5
ac4
ac3
ac2
ac1
ac0
1
0
D7
D6
D5
D4
D3
D2
D1
D0
1
1
D7
D6
D5
D4
D3
D2
D1
D0
ACM1602データ表よりアレンジ
上記のコマンドを送ればその設定になります。
液晶の文字のアドレス
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10・・・・・39 3A 3B 3C 3D 3E 3F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50・・・・・79 7A 7B 7C 7D 7E 7F
液晶の画面は上のようなアドレスになっています。
LCD初期化
#include <Wire.h>//I2C接続
void setup() {//初期設定部
Wire.begin();
initLcd();//LCD初期化
}
void loop() {//繰り返し部
}
//関数・サブルーチン
void writeCmd(byte cmd){//コマンド送信
Wire.beginTransmission(0x50);
Wire.write(0x00);//第1BYTE
Wire.write(cmd); //第2BYTE
Wire.endTransmission();//ストップ
}
void writeData(uint8_t dat){//データ送信
Wire.beginTransmission(0x50);
Wire.write(0x80);// 第1BYTE
Wire.write(dat); // 第2BYTE
Wire.endTransmission();//ストップ
}
void initLcd(){//LCD初期化
delay(10);writeCmd(0x01);//ディスプレイ空白
delay(10);writeCmd(0x38);//データは 8bit
//2行表示,フォントサイズ 5x8
delay(10);writeCmd(0x0c);//表示開始
//カーソル使用,カーソル場所使用
delay(10);writeCmd(0x06);//モードセット
//インクリメント,シフト表示なし
delay(10);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
同じように上記のサブルーチンを書き足せ,setCursor(x,y);でカーソルを思う位置に移動できます。
カーソル移動
initLcd()のサブルーチンを付け加えると初期設定でinitLcd()が使えて,LCDを白紙にしてくれます。
void setCursor(byte col, byte row){//カーソル移動
byte rowOffsets[] = { 0x00, 0x40 };//1行の文字数
if ( row > 1 ) {row = 1;}
writeCmd( 0x80 | (col + rowOffsets[row]) );
}
文字表示
writeData(0x31);//"1"文字コード出力
writeData(0x41);//"A"文字コード出力
writeData(0xB1);//"ア"文字コード出力
文字はwriteDataで任意の出力ができます。文字列表示のためのサブルーチンも書けます。
文字列表示
void strPrint(char *str) {//文字列出力
for(int i = 0; i < 20; i++) {
if(str[i] == 0x00) {break;}
else {writeData(str[i]);}
}
}
消費電流
strPrint("test");
と記述すればtestと表示します。
Arduinoを含めて100mA消費しています。
数字表示
2017年6月25日
SO1602A
有機EL16×2キャラクタディスプレイです。
見た目はI2C液晶とかわりませんがセルそのものが光るので高輝度で見やすく,消費電力も少ない液晶?表示器です。
数字の表示は1桁なら0x30+nと容易に表示できますが,桁が固定していない場合はとても難しくなります。10以上なら10で割って整数にして10をかけて元の数から引くと最下桁の数字が得られます。これを繰り返すと数の羅列が得られます。少数はもっと複雑になります。
数字と文字の分別もしなければならないし,表示するだけでも結構大変なことなのですね。
ライブラリがなければ全て作らなければいけないのです。
I2CアドレスはSA0をLで0x3C,Hで0x3D
手前右に見えている端子は,右から1番pin
一番左が14pinですがこの写真では9番pinまでしかハンダ付けしていません。
実はこの写真は上下が反対で表示は逆さまになります。
1pinGND,2pinVDD(3.3V)
7pinSCL,8pinSDA_in,9pinSDA_out
(3.3kΩでプルアップ)
3pin/CS(接地)
4pinSA0(接地0x3C)・・・VDDならば0x3D
配線はプルアップ抵抗と電源低下補償コンデンサと接地だけで,Arduinoとは電源とSDC/SCLの4本で接続できます。
プルアップ抵抗やコンデンサ・ジャンパ等はLCD基板上に配線するといいとアドバイスがあります。
マイクロチップにもライブラリはあるのですが,SO1602Aの場合はソフトでコントラストを調節するので,コントラストがデフォルトで0ならば表示はできないことになります。I2Cでコントロールすればいいのですが
http://n.mtng.org/ele/arduino/i2c.htmlに行くと対応するライブラリがあります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <I2CLiquidCrystal.h>//ライブラリ
#include <Wire.h>//I2C接続
I2CLiquidCrystal lcd(0x3c, (uint8_t)127);//実体作成(変更)
//I2Cアドレス
// コントラスト
void setup() {
lcd.begin(16,2);//液晶初期化 2行16文字
}
void loop() {
lcd.print("I'm here");//液晶に表示
}
これで動きます。後は他の液晶の使い方と同じです。
コントラストの調整は少々お待ち下さい。
ELは電力消費が少なくdigitが発光するため見やすくなっています。
Meteoで130mA消費していましたが消灯時と変わらない30mA~40mAで済んでいます。
1602Aと比べてdigitが発光するのでとても見やすいです。
ブレッドボードに組んでいた回路を液晶モジュールに組み込みました。初めに部品を用意して,配置し,ハンダ付けしました。
配線がすっきりしました。まさしく4線での接続ができるようになりました。
しかし,I2Cの考え方からするとプルアップ抵抗はArduinoの方に付けるべきなのかもしれません。
Arduino込みで30~40mAで動いています。
完成したディスプレイは4線で接続できます。1,2番pinはGND,5Vです。7番pinはA5,8番pinはA4へ接続します。I2C接続です。
Arduino側の配線です。I2C用の4線ポートを作りたいところですが,今回はこれで済ませています。
SPI
検討中です。
bluetooth
検討中です。
wifi
検討中です。
赤外線通信
受信
リモコンの通信の内容がわかれば送信もできます。
まずは受信しましょう。
受光器は950nmで38KHz変調だけに反応する専用品です。
装置は簡単です。HX1838という3端子の赤外線リモコン用受信機を写真のように取り付けるだけです。
受光部分を手前にして左がデータですので足を少し曲げてメスオスのジャンパ線を使って11番pinに接続します。
真ん中がGND,右が5Vですのでpinヘッダにそのまま差し込みます。
シリアルモニタ
Arduinoが何を言ってくるか見るためにシリアルモニタを使います。
ASCIIコード表です。例えば「A」は0401Hです。
スケッチ
送信
InfraRed01_6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#define READ_PIN 11//赤外線入力
int data[50];
int clok[50];
//初期設定
void setup(){
Serial.begin(9600);//通信速度
pinMode(READ_PIN,INPUT);//入力
Serial.println("Ready");}//合図
//繰り返し
void loop() {
for(int i=0;i<50;i++){//data読み込み
clok[i]=LOWS();
data[i]=HIGS();}
for(int i=0;i<50;i++){//表示
Serial.print(clok[i]);Serial.print(",");
Serial.print(data[i]);Serial.print(",");
}
Serial.println("END");
}
int HIGS(){
unsigned long ms = micros();//HIGの開始時刻
while(digitalRead(READ_PIN)==1){;}//HIGH時間
return (micros()-ms)/10;}
int LOWS(){
unsigned long ms = micros();//LOWの開始時刻
while(digitalRead(READ_PIN)==0){;}//LOW時間
return (micros()-ms)/10;}
95684,855,430,
37,153,37,42,40,153
赤外線のLOWとHIGHの時間を測定して信号にして解析しようとしてみました。
色々なスケッチを参考にさせていただき,できる限りシンプルにしてみました。
改行
データは長いので横スクロールしてしまい,読めなくなってしまいます。自動改行の方法がわからないので,最初は3データ次からは12データごとに改行するようにしました。
データの解析
データが得られたので解析します。
NEC、日立、東芝、ビクター、サンヨー、松下、パイオニアがNECフォーマットなのでこれを解析します。
信号のフォーマット
赤外線は950nmを使い38KHzで変調するとのことです。
Leaderと呼ばれる信号の初めを表す部分が有ります。HIGHは16T*560=8960μSです。LOWは8T*560=4480μSです。1Tは560μSです。
サンプルデータは1/10になっています。
サンプルデータ
電源,1,2,3のボタンを押したときのサンプルデータです。
データ収集
データのLOWの部分の時間を測定してみました。Hが350μS,Lが450μS前後です。
データHIGHのLは1560μS前後です。
カスタマコードは16進数でA23Dhこれがメーカの製品のIDとなるものでしょう。4つのサンプルとも同じです。
電源ONのデータコードは48hです。
1は79h,2はE8h,3はB9hです。どのような規則性が有るのでしょう?
シリアル通信
ほとんどのキーを読み取りましたが半日かかってしまいました。
色々と手を加えることができる独自のシリアル通信があると便利です。
サンプルデータを目で追ってキーに割り当てられた内容を読み取りました。
VBデータ収集
VBでForm1.VBデザインで上の図のようにForm1を作ります。それぞれのアイテムのNameを変更します。右上のワード文章はFormの中身のプログラムです。
ボーレイトを設定し損ねて文字化けが2日続きました。以前の失敗で学習しないのが困りものです。
なんとか動き始めました。
人間の目は大したもので機械ではすぐに解析できそうもないこんなデータでも規則性を見つけることができそうです。
データ16進数
VBでデータを読み込むと数字が文字になるので,Arduinoでもう少し整えて送信します。
2018/1/25
InfraRed03_5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#define READ_PIN 11//赤外線入力
int data[100];int clok[100];int onof[100];
void setup(){//初期設定
Serial.begin(9600);//通信速度
pinMode(READ_PIN,INPUT);//入力
Serial.println("Ready");//合図
}
void loop() {//繰り返し
int i=0,n=0,m=0,beg=0;
for(i=0;i<100;i++){//data読み込み
data[i]=HIGS();//H時間
clok[i]=LOWS();//L時間
if(beg==1 && 400<data[i] && data[i]<600){beg=2;n=i;}//頭出し
if(beg==0 && 600<clok[i] && clok[i]<999){beg=1;}//L800H400
}
for(int i=n+1;i<100;i++){//データon,off抜き出し
if(clok[i]<30 || 200<clok[i]){n=i;i=0;break;}//はみ出し監視
if(data[i]<30 || 200<data[i]){n=i;i=0;break;}//はみ出し監視
if(data[i]<100){onof[m]=0;m++;}//off
if(100<data[i]){onof[m]=1;m++;}//on
}
for(int i=0;i<8;i++){//16進数取得
m=onof[i*4+0]*8+onof[i*4+1]*4+onof[i*4+2]*2+onof[i*4+3];
Serial.print(String(m,HEX));//出力
}
Serial.println("");//改行
}
int LOWS(){
unsigned long ms = micros();//LOWの開始時刻
while(digitalRead(READ_PIN)==0){;}//LOW時間
return (micros()-ms)/10;}
int HIGS(){
unsigned long ms = micros();//HIGHの開始時刻
while(digitalRead(READ_PIN)==1){;}//HIGH時間
return (micros()-ms)/10;}
Arduinoのスケッチです⇒
コピーしてArduinoI.D.Eに
貼り付けます。
ライブラリを使う
ライブラリは便利です。
serial04_1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <IRremote.h>//ライブラリを使用
int RECV_PIN = 11;//入力pin
IRrecv irrecv(RECV_PIN);//インスタンス作成
decode_results results;//解析結果
void setup(){//初期設定
Serial.begin(9600);//通信開始
irrecv.enableIRIn(); // Start the receiver
Serial.println("ready");//合図
}
void loop() {//繰り返し
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);//結果を16進数で出力
irrecv.resume(); // Receive the next value
}
delay(100);//0.1秒待ち
}
サンプルプログラムです。注釈を加えました。
ハードや信号の役割を知るためにはライブラリなしで練習すると勉強になります。
手軽に作るにはライブラリが便利です。
出力サンプル
出力サンプルです。左がライブラリなし,右がライブラリ有りです。
大文字小文字の違いはありますが同じ結果になっています。
2018年1月29日(月)
2週間かかりました。
赤外線で通信 送信
受光器は950nmで38KHz変調だけに反応する専用品です。
送信には38KHzの変調をかけなくてはなりません。
赤外線LEDの+極をDP(デジタルpin)3のPWMに繋ぎます。-極は220Ωの抵抗を通してGNDへジャンパ線で接続します。
PWM駆動なので抵抗は要らないという説もありますが,しばらくは接続しておきます。
シリアルモニタ
送信のためにもシリアルモニタは必要です。VBで作ったモニタを使います。
スケッチ
InfraRed05_3_send
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <IRremote.h>//ライブラリ読み込み
IRsend irsend;//インスタンス作成
void setup(){//初期化は必要なし
}
void loop() {//繰り返し
int khz = 38; // 38kHz carrier NEC
unsigned int irSignal[ ] = {データ}; // RAW
irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); //波長計算
delay(5000); //5秒待機
}
ライブラリを使って簡単な送信プログラムを作ります。
データ
9000, 4500,
560, 1560, 560, 560, 560, 1690, 560, 560,
560, 560, 560, 560, 560, 1560, 560, 560,
560, 560, 560, 560, 560, 1560, 560, 1690,
560, 1690, 560, 1560, 560, 560, 560, 1560,
560, 560, 560, 1560, 560, 560, 560, 560,
560, 1560, 560, 560, 560, 560, 560, 560,
560, 1690, 560, 560, 560, 1690, 560, 1560,
560, 560, 560, 1690, 560, 1690, 560, 1690,
560, 39416, 9000, 2210, 560
データは4bit毎に区切ってあります。
データは長いのですが,プログラムは簡単です。
これで電源OnOffができました。
学習リモコン
受信して収集した赤外線波形をそのまま出力すれば,学習リモコンとして成立します。データ量は多くなりますがストレートです。
赤外線通信のデータ受信スケッチserial01が有効です。
送信波形
NECグループの通信波形は560*16μ秒HIGHTを送信後560*8μ秒待機でLeaderとなりその後32bitの信号が続きます。
NECフォーマットをもう一度載せます。
信号のフォーマット
データが得られたので解析します。
赤外線は950nmを使い38KHzで変調するとのことです。波長は26.3μSです。
Leaderと呼ばれる信号の初めを表す部分が有ります。1Tは560μSとなっていますのでHIGHは16Tで8960μSとなります。LOWは8Tで4480μSです。
1Tは560μ秒 HIGH 565μ秒 LOWで"0",
560μ秒 HIGH 1695μ秒 LOWで"1"
です。
38KHz
InfraRed05_send
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#define WRITE_PIN 3
void setup(){//初期化
Serial.begin(9600);
pinMode(WRITE_PIN,OUTPUT);
Serial.println("Ready");
}
void loop() {//繰り返し
int khz = 38; // 38kHz 26μS
unsigned long ms=micros();
Serial.println(micros()-ms);
ms=micros();
H();
Serial.println(micros()-ms);
delay(5000); //5秒待機
}
void H(){//560μS
for(int i=0;i<21;i++){//21回繰り返す
digitalWrite(WRITE_PIN,1);
delayMicroseconds(7);
digitalWrite(WRITE_PIN,0);
delayMicroseconds(14);
}
}
560μSのHIGHTシグナルを作るために38KHz=26μSのキャリアであれば約21回の繰り返しになります。
上のserial05_sendでシリアルモニタを使って呼び出し時間を測定します。
約580μSになっています。
21回繰り返しを340回にすると約8960μSになりました。ほぼOKだと思います。
ライブラリ無し
ライブラリを使わないでプログラムを作ります。
serial050_send
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#define WRITE_PIN 3
void setup(){//初期化
Serial.begin(9600);
pinMode(WRITE_PIN,OUTPUT);
Serial.println("Ready");
}
void loop() {//繰り返し
HH();
delayMicroseconds(4480);
HS();LS();HS();LS();LS();LS();HS();LS();
LS();LS();HS();HS();HS();HS();LS();HS();
LS();HS();LS();LS();HS();LS();LS();LS();
HS();LS();HS();HS();LS();HS();HS();HS();
LS();delayMicroseconds(39416);HH();LS();
delay(1000); //1秒待機
}
//補助部
void HH(){//8965μS Leadyの初めの送信
for(int i=0;i<16;i++){//16回繰り返す
KHz38();
}
}
void HS(){//560+1695μS 1の送信
KHz38();
delayMicroseconds(1680);
}
void LS(){//560+565μS 0の送信
KHz38();
delayMicroseconds(560);
}
void KHz38(){//38KHzで発信
for(int i=0;i<21;i++){//21回繰り返す
digitalWrite(WRITE_PIN,1);
delayMicroseconds(8);
digitalWrite(WRITE_PIN,0);
delayMicroseconds(12);
}
}
void Time(){//発信時間測定
int khz = 38; // 38kHz 26μS
unsigned long ms=micros();
Serial.println(micros()-ms);
ms=micros();
HH();
Serial.println(micros()-ms);
delay(5000); //5秒待機
}
serial050_send
正常に動作しました。赤外線LEDを直接接続しても損傷しませんでした。
+ -を間違えなければ写真のように点滅します(赤外線はカメラだと見えます)。
一晩中付けっぱなしにしてしまい赤外線LEDは切れてしまいました。
16進数送信
InfraRed054_send
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#define WRITE_PIN 13
void setup(){//初期化
Serial.begin(9600);
pinMode(WRITE_PIN,OUTPUT);
Serial.println("Ready");
}
void loop() {//繰り返し
//送信データ
int HL[]={1,0,1,0,0,0,1,0,0,0,1,1,1,1,0,1,//メーカ
1,0,0,1,0,1,0,1,//データ
0,1,1,0,1,0,1,0};//!データ
int hex=0xaa;//Hexデータ
for(int i;i<8;i++){//変換
int a=hex/2;
HL[23-i]=(hex-a*2);
HL[31-i]=!HL[23-i];
hex=a;
}
for(int i=0;i<8;i++){
HL[16+i]=d;HL[24+i]=!d;
}
HH();//8965μS
delayMicroseconds(4480);
for(int i=0;i<32;i++){//
if(HL[i]==1){HS();}//2256μS
else{ LS();}//1125μS
}
LS();delayMicroseconds(39416);HH();LS();
delay(1000); //1秒待機
Serial.println();
}
//サブルーチン
void HH(){//8965μS Leadyの初め送信
for(int i=0;i<336;i++){//336回繰り返す
digitalWrite(WRITE_PIN,1);
delayMicroseconds(7);
digitalWrite(WRITE_PIN,0);
delayMicroseconds(15);
}
}
void HS(){//560+1695μS 1の送信2255
KHz38();
delayMicroseconds(1680);
}
void LS(){//560+565μS 0の送信1125
KHz38();
delayMicroseconds(560);
}
void KHz38(){//38KHzで送信
for(int i=0;i<21;i++){//21回繰り返す
digitalWrite(WRITE_PIN,1);
delayMicroseconds(7);
digitalWrite(WRITE_PIN,0);
delayMicroseconds(14);
}
}
16進数でデータを与え薄い黄色のプログラムで2進数に変換します。!dataも自動で計算することができます。
HL[ ]の配列に格納されたデータを薄い緑の分岐命令で薄い赤でサブルーチンHIGHとLOWを呼び出します。
パソコンでコマンド送信
送信ボックスにカスタマコードとコマンドを入れてArduinoに送りっ赤外線を送信するようにします。
コマンドに入っているデータを16進数にして変数nmに格納します
反転データも255-nmで自動計算します。
送信ボックスにカスタマコードとコマンドを入れてArduinoに送りっ赤外線を送信するようにします。
コマンドに入っているデータを16進数にして変数nmに格納します
反転データも255-nmで自動計算します。
VBのプログラムです。⇒
コピーしてVBに
貼り付けます。
送信して10進数で返してきました。この数を計算してArduinoで2進数を作ります。
Arduinoで16進数→2進数変換
例えば123という数字から2進数を作る場合は整数値で2で割ると61になります2倍すると122です。123から122を引いて1が一番下の桁になります。
123 (123/2)*2=122 1
61 (61/2)*2=60 1
30 (30/2)*2=30 0
15 (15/2)*2=14 1
7 (7/2)*2=6 1
3 (3/2)*2=2 1
1 1
123=1111011 8bitにすると01111011となります。
16進数を2進数変換するプログラムです。
if(c>255){
for(int i=0;i<16;i++){//2進数に変換
int a=c/2;
HL[15-i]=(c-a*2);
c=a;
}
}
0bitから15bitはカスタマコードが入ります。
for(int i=0;i<8;i++){
int a=hex/2;
HL[23-i]=(hex-a*2);//コマンド
HL[31-i]=!HL[23-i];//反転
hex=a;
}
16bitから23bitはコマンドが入ります。24bitから31bitはコマンドの反転データが入ります。
Arduinoのプログラムです。⇒
コピーしてArduinoI.D.Eに
貼り付けます。
上のVBプログラムからカスタマコードとコマンドを送ると赤外線でリモコンできます。
2018/2/24(土曜日)
シリアルモニタ
ArduinoI.D.E.にもシリアルモニタは付属していますしTeratermという優れた通信ソフトもありますが,せっかくなので自前のシリアルモニタを作ります。色々手を加えて必要な機能を付け加えることができるからです。
ポート名を取得
テキストボックスとコンボボックスをフォーム1に貼り付けます。
ポートオープン
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'ポートネームを取得
Dim ports As String() =SerialPort.GetPortNames()
ComboBox1.Items.Clear()
'コンボボックスにポートネームを格納
Dim port As String
For Each port In ports
ComboBox1.Items.Add(port)
Next port
'0番目を選択して表示
If ComboBox1.Items.Count > 0 Then
ComboBox1.SelectedIndex = 0
End If
'ポートネームが有ればポートネームを選択
If ComboBox1.Text <> "" Then
SerialPort.PortName = ComboBox1.Text()
End If
'できれば(try)ポートを開く
Try
SerialPort.Open()
TextBox1.Text = "open"
Catch ex As Exception
TextBox1.Text = "couldnt"
End Try
2行目でポートの名前を取得します。
4行目から9行目でコンボボックスにポート名を格納します。
以下ポートネームを選択してオープンします。
21行目からのTry文は失敗してもフリーズしないための手立てです。
VBでのデザイン
VBを使って簡単な送受信を作成します。
Form1のデザインです
ラベルは見た通りですが各ボタンとボックスは(Name)に名前を付け直します。
右側のワードデータをVBのコードに貼り付けます。
受送信
実際に使ってみましょう
Serial_readwrite00
//PC側から受信して
//Arduinoでそのまま送信。
//
//宣言
int str=0;//数字
//初期設定
void setup() {
Serial.begin(9600);//初期化
}
//繰り返し
void loop() {
if (Serial.available() > 0) { // 存在するか?
delay(10);//バッファの充足を待つ
int sav=Serial.available();
for(int i=0;i<sav;i++){
if(Serial.available() > 0) { //存在すれば
str =Serial.read(); // 読み込む
Serial.print(str);//送信
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(Serial.available() > 0)
でシリアルのバッファを調べてDETAが存在すれば
バッファの数(sav)だけ
for(int i=0;i<sav;i++){
と繰り返して
str =Serial.read();
でstrに読み込みます。
読み込んだDATAは
Serial.print(str);
で出力します。
テスト
シリアルモニタでは"1"をVBで
SerialPort.WriteLine(送信ボックス.Text)
を使って送信します。
送信ボックスに"1"を入力して送信ボタンを押します。
4910と返してきました。49は"1"を表すアスキーコードです。10は文字終了を表しています。
"123"を送信すると
"49505110"とかえしてきます。
パソコンと通信
シリアル通信はASCII文字で送受信します。0から255までの数字が表す文字を送ることはできますが数は送れないということになります。
百二十三という数字を送りたい時はマイコン側で変換しなければならないということです。
シリアル通信にはアスキーコードが使われています。
ASCIIコード表です。例えば"A"は0x41で表現されます。10進数では65になります。
文字列の受信
SerialPort.WriteLine(送信ボックス.Text)
の代わりに。
SerialPort.WriteLine(Convert.ToInt32(送信ボックス.Text, 16))
を使って送信すると16進数を変換して送信できます。
10進数の受信
10進数を受信するプログラムです。
//宣言
int str=0;//数字を記憶する変数
unsigned long dec=0;//数字を記憶する変数
unsigned long keta=1;//数字を記憶する変数
桁や10進数は3桁を超えるとintではオーバーしてしまうのでunsignd longで計算します。
//初期設定
void setup() {
Serial.begin(9600);//serial初期化
}
初期設定はシリアル通信だけです。
if (Serial.available() > 0) { // 存在するか?
delay(50);//バッファの充足を待つ
int sav=Serial.available();
str=0;
keta=1;
dec=0;
シリアルバッファにデータが存在すると
Serial.available() に個数が入力されます。
1以上ならば50m秒待ってデータが入り終わるまで待ちます。
10m秒だと9桁までしか入りません。
savに桁数+2が入ります。
for(int i=0;i<sav-2;i++){//桁を決める
keta=keta*10;
}
keta=1;
for(int i=0;i<sav-2;i++){//桁を決める
keta=keta*10;
}
最後に1013が入っていますので桁はsav-2桁になります。13は表示されません。
for(int i=0;i<sav;i++){
if(Serial.available() > 0) { //存在すれば
str =Serial.read(); // 読み込む
if(47<str && str<58){//10進数字ならば
str=str-48;//数にする
dec=dec+str*keta;keta=keta/10;
//桁を揃える
}
//Serial.print(str);//送信
}
}
Serial.println(dec);
savは最後まで使わないと1013が残ってしまうので最後まで読みます。
終わったら
変数decを送信します・
10進数を読み込む
一文字を受信することは簡単にできますが,文字列の受信には工夫が必要です。
Serial_read_dec01
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//PC側から受信して
//Arduinoで変数に10進数で格納
//変数を送信
//宣言
int str=0;//数字を記憶する変数
unsigned long dec=0;//数字を記憶する変数
unsigned long keta=1;//数字を記憶する変数
//初期設定
void setup() {
Serial.begin(9600);//serial初期化
}
//繰り返し
void loop() {
if (Serial.available() > 0) { // 存在するか?
delay(50);//バッファの充足を待つ
int sav=Serial.available();
str=0;keta=1;int dec=0;
for(int i=0;i<sav-2;i++){//桁を決める
keta=keta*10;
}
for(int i=0;i<sav;i++){
if(Serial.available() > 0) { //存在すれば
str =Serial.read(); // 読み込む
if(47<str && str<58){//10進数字ならば
str=str-48;//数にする
dec=dec+str*keta;keta=keta/10;//桁を揃える
}
//Serial.print(str);//送信
}
}
Serial.println(dec);
}
}
これで10桁までの10進数を読み込むことができます。
16進数の場合は変数はhexにしてketaに掛ける,割る数は10の代わりに16にします。
3桁以上は long hexにします。unsignd long hexならば8桁まで変換してくれます。