jl7gmnのblog

yahooブログから移行してきました。アマチュア無線を中心としたブログです。

2011年07月

vbausbio.dllをVisual C++2010 その11

イメージ 1

5000文字制限のためのその10の続きです。
添付する画像がなかったのでシリアルインターフェース(Arvel)を載せました。
以下つづきになります。
--------------------------------------------------------------------------------
ここの部分は前後しますがトップのグローバルスコープエリアに桁の重みの固定値を設定しておきます。
const int KAIJ0=1;
const int KAIJ1=16;
const int KAIJ2=256;
const int KAIJ3=4096;
const int KAIJ4=65536;
const int KAIJ5=1048576;
const int KAIJ6=16777216;
const int KAIJ7=268435456;
--------------------------------------------------------------------------------
   GOUKEI = ( KAIJ7 * VALSUCHI[2])+(KAIJ6 * VALSUCHI[3])+(KAIJ5 * VALSUCHI[4])+(KAIJ4 * VALSUCHI[5])+(KAIJ3 * VALSUCHI[6])+(KAIJ2 * VALSUCHI[7])+(KAIJ1 * VALSUCHI[8])+(KAIJ0 * VALSUCHI[9]);

   int Frequency=0;
   Frequency=(GOUKEI * 0.625);//周波数を求めます。小数点等はなしの数値のみ

   // 周波数の数字の集まりですが区切りを表す"."がないので周波数範囲で表示用に組み立てます。
   String^ mojiFreq;       //周波数を文字化して入れる変数
   mojiFreq=Frequency.ToString();      //文字化します。
   int lenFrequency=0;       //文字化の長さ用
   lenFrequency=mojiFreq->Length;      //長さを求めます。
   array<String^>^awasu=gcnew array<String^ >(10); //表示用の配列
array<String^>^mojika=gcnew array<String^ >(lenFrequency);//抜き出した1文字ごとの周波数データ用配列
int lpc=0;
   for (lpc=0; lpc<=lenFrequency-1 ;lpc++){
mojika[lpc]=mojiFreq->Substring(lpc,1); //一文字を周波数文字列から抜き出して配列へ
   }
--------------------------------------------------------------------------------
上記のGOUKEIに0.625Hz(STEP)をかけると(Hz)での周波数が求まります。
以上で周波数の表示データが一応は求まったことになります。このままでもいいのですが、やはり無線機の表示と同じ表示にしたい願望が出てきます。
たとえば上記のプログラムで求めた周波数データは周波数が
21.192.00
の場合は
21192000
というデータでもとまっていますのでこれを無線機の表示とあわせるための変換を行います。最後の0は表示では出ていないので、使いません。
プログラムではFrequencyデータを文字化して、文字長を出します。この文字長が無線機の周波数表示では次の3種類に分類されます。6桁(1MHzより下)、7桁(1MHzより9.99999MHzまで)、8桁(10.000.00MHzより30.000.00MHzまで)データではもう一桁ありますが、無線機では表示されていません。上記の周波数データとしては0がもう一つあります。表示部のコーディングを画像で載せています。5000文字制限でこのページはその11になっています。画像はその10にあります。

またコードを全部は載せてはいませんが、使った配列の宣言がバイト型とストリング型配列の場合の主な宣言方法は以下の2つです。
---------------------------------------------------------
array<Byte>^ bin;
bin=gcnew array<Byte>(16);
一行では
array<Byte>^ bin=gcnew array<Byte>(16);
---------------------------------------------------------
array<String^>^binasc=gcnew array<String^ >(16);
---------------------------------------------------------
また16進の文字への変換方法は
int aa=16;
int abc=0;
for(abc=0;abc<=aa-1 ;abc++){
binasc[abc]=bin[asc].ToString("X");
}
---------------------------------------------------------
以上ざっと書きましたが、今回多用した配列arrayの場合のエラーとして、カッコがありました。最初はまったく気がつきませんでしたが、VisualBasicのときの配列と同じ()のカッコを使ってしまったためにエラーが出ました。C++では[]です。
---------------------------------------------------------
以上で周波数表示用のラベルには無線機と同じ周波数の表示をするルーチンができたことになります。コードでは追加してありますが、タイマーコントロールを追加して、スタートボタン押下にて周波数を定期的に読み取り表示するようにしてあります。タイマールーチンでは ボタン21に割り当てた今回のコードを以下のように呼び出しています。止める場合のボタンも追加しています。このようにするととても簡単です。
-------------------------------------------------------------------------------
private: System::Void timer3_Tick(System::Object^ sender, System::EventArgs^ e) {
button21_Click(sender,e);
}
-------------------------------------------------------------------------------
private: System::Void button22_Click(System::Object^ sender, System::EventArgs^ e) {
timer3->Interval=500;
timer3->Start();
}
-------------------------------------------------------------------------------
private: System::Void button23_Click(System::Object^ sender, System::EventArgs^ e) {
timer3->Stop();
}
-------------------------------------------------------------------------------
タイマー3開始のボタンを押すと無線機からのデータをリアルタイム(500msec毎)に読み取るようになります。無線機の周波数ダイアルを動かすと周波数のラベル表示もあわせて動きます。本日はこれにておしまい。次はタイマー動作時の表示追加とか、sメータの表示にしようか?それとも、コードの整理をしようか、とにかく暑いので風呂に入って汗をながしたいと思う。つづく 本当??

vbausbio.dllをVisual C++2010 その10

イメージ 1

イメージ 2

シリアル通信による八重洲無線機FT-1000MPの周波数を読み取るプログラムにトライしてみた。とにかくVisualC++2010Expressは型変換については厳しい。単純にいって、私の場合は型変換エラーがほとんどを占めています。とは言っても学習しながらだからしょうがないか?。無線機の周波数を読み取るためのデータのやり取りは基本的にバイトデータにて処理を行っています。このためバイトデータから他の型への変換がかなりあります。桁処理もあるし、このため型変換で使うarray配列もかなり使用することになりました。VisualBasic2008Expressのように単純にString配列のみですべてコーディングとはいかない。とにかく今まで出したエラーは型変換が一致していないためのエラーがほとんどだ。がしかし一度変換方法がうまく設定できると後は、応用ができる。ここまでくる過程が実は一番楽しいところである。前置きはこれぐらいにして、本題だが、基本はモード変更と同じくパラメータとコマンドをRS-2323Cで無線機に送ることが最初のステップである。FT-1000MPの場合はCATコントロールコマンド表の中で言うと、No.14のコンファーム・リクエストである。
10,P1, ※ , ※ ,P4
がコマンドとパラメータ構成で表示データ読み出しなのでP1が02、P4はにメモリ読み込みは使わないので 00にする。
10,02,00,00,00
が対応するパラメータコマンドとなる。まずはこれを今回は関数化したft-1000mpcomを使わずに直接書いてゆきます。これは周波数読み取りのコマンドボタンに対応させますが、タイマーコントロールを用意して、このボタンをコールし、タイマーインターバル間隔で連続読み取りにしてゆきます。
データは上記のcntcomdat="1002000000"をセットし、各シリアルポート条件を設定しポートを開きます。その後送るデータを加工して、_serialPort1->Write(kako,0,comlength);で送出します。ここからがシリアルポートへのコンファーム・リクエストコマンドによるデータの読み出し処理となります。最初のトラブルは、次の一行でデータを一回で読み取れると思っていたのですが、デバッグ状態ではうまく全部読み取れますが、ブレークポイントを全てはずすとたった1バイトしか読み出せない状況となりました。原因は不明です。
--------------------------------------------------------------
serialPort1->Read(bin,0,16);
--------------------------------------------------------------
なので上記の方法は止めて、1バイト読みする方法をとりデータ数分のループを行い全部のデータを取り込む方法へ変更しました。なお既定のバッファサイズは4096ですが、今回のデータでは16個(16バイト)なので以下のように設定しループで読み取っています。
--------------------------------------------------------------
int aa=16;
int ac=0;
for(ac=0 ; ac<=aa-1 ;ac++){
bin[ac]=_serialPort1->ReadByte();
}
--------------------------------------------------------------
ここで上記のbin[]にバイトデータで周波数データが16個入ります。
ここまでくれば安心します。周波数のデータかどうかはわかりませんが、データらしきものが取得できているという事が、とてもうれしくなります。
次は上記の読み取ったデータ郡を16進の文字に変換します。変換したデータは1桁と2桁になるため、常に2桁になるように1桁の場合には"0"をつけてあらためて書き直します。ここが意外と何でかという疑問がわいてきますが、周波数の算出にかかわるということがあるために必要な処理ということになります。16バイトのデータ中の1から4までのバイナリーとしての範囲は00027100~02DC6C00(Hex) LSB=0.625Hz(step)となっています。これは10進で160000~48000000(10進)ステップの0.625Hzをかけると 100000~30000000とFT-1000MPの受信周波数範囲単位(Hz)となることより16進の4バイトのデータがフルでいることがわかります。ここで1バイトとは8ビットのことです。16進でたとえば1だとすると2進の4ビットで0001ですが、データとしては1バイト必要ですから実際は上位の4ビットが必要になるわけです。0000と0001で全部で8ビットの1バイトということです。ここで1桁のデータには0をつける必要が出てくるのです。1(hex)のデータは 01(hex)ということです。ということで周波数の計算も上記の各4バイトのデータ値の合計を求めて0.625をかけることで周波数がHz単位で求まることがわかります。つまり2バイト目からのデータが4バイト分周波数データなので、周波数の4ビット毎の各桁の値(10進値)に重みデータにかけて値を出しそれぞれを和算してから0.625をかけることになります。
重みをかける16進値は文字から次の変換で10進化しておきます。以下にここの関係するコードを記します。
-------------------------------------------------------------------
array<String^>^binasc=gcnew array<String^ >(16);
int abc=0;
for (abc=0 ; abc<=aa-1 ;abc++){
binasc[abc]=bin[abc].ToString("X");
//  binasc[abc]=String::Format("{0:x}",bin[abc].ToString("X"));//これもOK
  }
int lenasc;
int abc1=0;
for (abc1=0 ; abc1<=aa-1 ; abc1++){
lenasc=binasc[abc1]->Length;
if( lenasc==1 ){
binasc[abc1]="0" + binasc[abc1];
}else{
binasc[abc1]=binasc[abc1];
}
}
array<String^>^KRE=gcnew array<String^ >(16);
Array::Copy(binasc,KRE,binasc->Length);// 配列をbinascからKREへコピーする
String^ WAKRE;//2桁ずつのデータをすべて連結しいれるための変数

WAKRE = (KRE[0]+KRE[1]+KRE[2]+KRE[3]+KRE[4]+KRE[5]+KRE[6]+KRE[7]+KRE[8]+KRE[9]+KRE[10]+KRE[11]+KRE[12]+KRE[13]+KRE[14]+KRE[15])->ToString();

//周波数計算
array<String^>^LRE=gcnew array<String^ >(32);
array<String^>^NRE=gcnew array<String^ >(32);
//一文字ずつ分けてLRE[31]配列にいれる
int abc2=0;
int ab=32;
for (abc2=0 ; abc2<=ab-1 ;abc2++){
LRE[abc2]=WAKRE->Substring(abc2,1);
}

//値変換10進にもどす
array<int^>^SUCHI=gcnew array<int^ >(32);
int abc3=0;
for (abc3=0 ; abc3<=ab-1 ; abc3++){
SUCHI[abc3]=(Int32::Parse(LRE[abc3], System::Globalization::NumberStyles::HexNumber));
}

int GOUKEI;
int VALSUCHI[10]; //10進化
VALSUCHI[0]=(Int32::Parse(SUCHI[0]->ToString()));// NO USE
VALSUCHI[1]=(Int32::Parse(SUCHI[1]->ToString()));// NO USE
VALSUCHI[2]=(Int32::Parse(SUCHI[2]->ToString()));
VALSUCHI[3]=(Int32::Parse(SUCHI[3]->ToString()));
VALSUCHI[4]=(Int32::Parse(SUCHI[4]->ToString()));
VALSUCHI[5]=(Int32::Parse(SUCHI[5]->ToString()));
VALSUCHI[6]=(Int32::Parse(SUCHI[6]->ToString()));
VALSUCHI[7]=(Int32::Parse(SUCHI[7]->ToString()));
VALSUCHI[8]=(Int32::Parse(SUCHI[8]->ToString()));
VALSUCHI[9]=(Int32::Parse(SUCHI[9]->ToString()));
--------------------------------------------------------------------------------
上記の16バイト中の+0のVALSUCHI[0]とVALSUCHI[1]の1バイト分はBANDNO:+1ら+4の周波数が属するバンドなので今回は使いません。周波数データであるVALSUCHI[2]~VALSUCHI[9]までの4バイトが計算で使う値となります。ほかの16バイト中のデータには+5、+6の2バイトがCLARF、+7の1バイトがモード(0=LSB,1=USB,2=CW,3=AM,4=FM,5=RTTY,6=PKT),+8がFILT(省略)、+9がFLAG、他+Aから+Fまでは未使用と割り当てられています。今回は上記の+1から+4に相当する部分だけ使います。
--------------------------------------------------------------------------------
5000文字制限のためこの続きは次にまわします。つづく

vbausbio.dllをVisual C++2010 その9

イメージ 1

イメージ 2

シリアル通信の無線機へのデータ送出を関数化してみた。使いかってがかなり良くなる。

String^ ft1000mpcom(String^ cntcomdat, String^ retda);

内容はcntcomdatにパラメータとコマンドをretdaには返り値(通常の送りコマンドのみでは"NONE"を入れて送ります。
コマンドボタンには以下の6行を記入するだけでモード変更ができます。
変えるのはcntcomdatのデータのみです。
例)
String^ retda;
String^ cntcomdat;
cntcomdat="0C01000000";
retda="NONE";// コマンド送りのみの場合に"NONE"に設定する
String^ backdata; 
backdata=ft1000mpcom(cntcomdat,retda);

上記の値設定でストリング変数のbackdataにはシリアル通信の受信したデータ(バイトからアスキーデータ変換したデータが入るように組む予定です。現在はretda:"NONE"をそのまま返しています。受信したデータとは、無線機のVFO読み取りデータ値、Sメータ信号のリクエストコマンドによる返り値と内部ステータス状態等を返すデータになると思います。通常のモード変更とかの送りのみのコマンドでは、送り時に設定した"NONE"をそのまま返します。
今現在の構想はハムログに周波数情報と相手のSメータ情報を送ることができたらいいと思っています。Sメータに関してはいろいろと大変そうな感じがあります。常に動いているということと、相手が出ているときに処理しなければならないということがあります。プログレスバーに表示することはいたって簡単ですが、どういうふうにSメータ値データを決定してハムログに送るかを考える必要があります。なおシリアル受信に関してはこの構想で対応する事になります。今現在は、Sメータ値は最大値とするのが手っ取り早いような気がしています。この場合、ノイズでSメータが振れる場合がありますが、まずは実際にやっていってから考えようと思います。まだ受信もできていないのに構想だけは進みます。コマンドを関数化したフォームを載せました。関数化部のコードは先のUSBボタンのコードに受け渡しの変数宣言部の追加部分を載せてプロト宣言した関数をコーディングします。コマンド送出は例のとおりパラメータとコマンドからなるデータを入れ替えてft1000mpcomに入れるだけで簡単に制御できるようになります。今日は本当に暑い。外気温は31.8℃、部屋は30.7℃窓は開けっ放しだが風はなし。パソコンのモニターからは熱が感じられる。そろそろパソコンを止めねば...熱中症には気をつけねば...おわり

vbausbio.dllをVisual C++2010 その8

イメージ 1

イメージ 2

新たに構想をしてみたことを書いてみる。
何かというと現在ハムログはパソコンからシリアルケーブルで無線機に接続されて直接周波数をハムログとの間でやり取りが行われているわけだが、今回はコントロールというか制御を別のプログラムで行い、プログラムが周波数データをハムログへ送るという形式をとるのがいいのではないかと思えた。ハムログと無線機だけの周波数読み取りのみで使用する場合はいいが、他の制御もしてみたい場合は、プログラムが主体になる必要があるためだ。ということで、何をしたいのかといいますと シリアル通信で無線機を制御するということです。遠隔操作にやるにしても直接のパソコン制御にしても無線機には通信機能がついているものがたくさんありますのでこれを利用するわけです。VisualC++2010Expressを用いたシリアル通信をやってみます。すでにVisualBasic2008Expressにて無線機のシリアル制御プログラムはできていますので、これをC++/CLI用に書き換えてみます。
私の使用している無線機はYAESU FT-1000MPです。この無線機はCAT機能用としてRS232C端子を標準で装備しています。また今回のプログラムでの制御コマンドも、テクニカルオーバービューのCATコントロールコマンド表の並びで利用できるようにして組みます。
表表示は コマンド、パラメータの並びで一覧表となっています。例えばMODE(電波型式)の切り換えはUSBモードの場合
コマンド:0C
パラメータ:01、※、※、※
となっています。※は特に関係ないが00を入れます。
コマンド、パラメータの並びは表とおなじですので、コマンドを並べる場合はとても簡単にできます。USBモードの送出データは 次のように準備します。
送出データ:0C、01、00、00、00
これはあくまでもわかりやすくコマンドを使うためです。実際の通信データは並び替えて送出します。実際に送るコードの並びは 00、00,00,01,0Cです。これは通信フォーマットに通信データの構成のなかにパラメータ4、パラメータ3、パラメータ2、パラメータ1、MSDコマンドというふうに書かれています。また通信の設定として
通信速度:4800ビット/秒
データ長:8ビット
スタートビット:1ビット
ストップビット:2ビット
パリティビット:なし
上記を主にプログラムのシリアル通信の設定値として他も含め下記のように初期設定します。ポートは今回は固定COM4(私の都合)で指定しました。
SerialPort^ _serialPort1;
_serialPort1 =gcnew SerialPort();
_serialPort1->PortName = "COM4";
_serialPort1->BaudRate = 4800;
_serialPort1->Parity=System::IO::Ports::Parity::None;
_serialPort1->DataBits=8;
_serialPort1->StopBits= StopBits::Two;
_serialPort1->Handshake = System::IO::Ports::Handshake::None;
_serialPort1->RtsEnable=true;
_serialPort1->Open();
(ここには送受信のコードを書く)
_serialPort1->Close();
通信の終了には必ず上記のClose();を行います。
ここまでは単純な設定ですので、書き方さえ間違わなければ問題はないと思います。実際は少し悩みました(ストップビットの例がOneしかなくで2の場合は数字か、とか実際に試してみてTwoであることがわかりました。)

今回は無線機の制御コマンドの上記のUSBモードにするためのコードをString変数に代入してこれを型変換を用いてシリアル送出用のデータに書き換えてから無線機のシリアルデータラインへ送ることを行います。
各配列を準備します。

array<String^>^indat=gcnew array<String^ >(10); //0から9のindat配列用意されます。
arary<String^>^bun=gcnew array<String^ >(5); // 0から4のbun配列用意されます。
array<Byte>^ kako;
kako=gcnew array<Byte>(5); // 0から4のバイト型kako配列用意されます。

上記の配列はcntcomdatに入れたデータを一旦String配列に入れて、なおかつ2文字ごとにまとめるという変換で使います。

cntcomdatにUSBデータをセットします。
次にデータの長さを求めます。10ですが...
----------------------------------------
String^cntcomdat="0C01000000";
nagasa=cntcomdat->Length;  
---------------------------------------- 
まずは1文字ずつの抜き出しを行いindat配列に入れます。
----------------------------------------
for (a1=0; a1<=nagasa-1 ; a1++){
indat[a1]=cntcomdat->Substring(a1,1);
}
----------------------------------------
次に2文字ごとにペアにします。
----------------------------------------
for (a4=0 ;a4<=comlength-1 ; a4++){
bun[a4]=indat[2*a4]+indat[2*a4+1];
}
----------------------------------------
シリアルにはバイト配列でデータを送るようになっているので変換をします。このときに先の送出用データ5個のデータの並び替えを行います。
----------------------------------------
kako[0]=(char::Parse(bun[4],System::Globalization::NumberStyles::HexNumber));
(以下同じ型式なので省略)
----------------------------------------
後はデータを送ります。comlengthはグローバル宣言でconstで5に初期化しています。送出後にシリアルポートを閉じます。
----------------------------------------
_serialPort1->Write(kako,0,comlength);
_serialPort1->Close();
----------------------------------------
上記の設定でプログラムのUSBコマンドボタンを押すと、無線機のモードがUSBに変わります。ボタン一つしかないと変わったかわからないので別にFMモードもボタン一つ追加してデータ以外はまったく同じコードで動かしています。同じコードでも動くところがCの強みですね。ちなみにコマンドは 
String^ cntcomdat="0C06000000"; // FM 
です。
コマンドで制御ができるようになるといろいろと試したくなると思います。VBでの制御ではいろいろとやりました。VisualC++2010Expressでもシリアル通信の送りと受けがありますので今回の送りは良しとして、受信も試していこうかと思います。まずはいろいろと調べる必要があります。何せC++/CLIは修行の身です。簡単にVBの書き換えでいけば良いのですが。。。。なんか最近は早朝のブログ作成が多くなってきたようだ。もう一眠りしようかしらん!少し眠くなってきた。おわり

vbausbio.dllをVisual C++2008 その7

イメージ 1

イメージ 2

プログラム(多重起動防止)についてプログラミングしてみた。いろいろと方法があるが、2つほど試しにやってみた。1つはMutexのプロセス管理方法、2目つはProcessメッソドを使った方法である。結果から言うと1つ目は、うまく動作していない。現在は保留状態である。なので今は動いているProcessメソッドを用いた方法を採用する。
内容はいたって原理的で、現在のプロセスに登録されている中に、起動しようとしているプロセス名があるかを調べて、そのブール値をもって判断する方法である。
メインは次の一行です。

Process::GetProcessesByName("hamlogw")->Length>0);

この一行を使ったif分分岐をハムログ起動のボタンの最初に書くだけです。画像でコードとメッセージボックス表示状態を載せました。いたって簡単に出来てしまいます。

 1つ目のMutexを使った方法はうまく動作していない。オーソドックスな方法なはずなのだが、どうも次のコード中のif分の判断が出来ていないようだ。
【未動作Mutex】-------------------------------------
using namespace System::Diagnostics;
using namespace System::Threading;

Mutex^ mu = gcnew Mutex(false,"Ham");
if ( mu->WaitOne(0,false) == false )
{
MessageBox::Show("Hamlogw.exeは起動中です。");
return;
}else{
先のハムログ起動コード(省略)
......
mu->ReleaseMutex(); //Mutexの開放
}
----------------------------------------------------
このMutexを使った方法は後で再度やってみたいと思っている。
最近は朝にブログを書くようになってしまった。しかし朝早い時間帯は静かでとても心が休まる。MusicTVで洋楽を流しながらコーディングするのも乙なものだ。
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード
アーカイブ
  • ライブドアブログ