チョコっとカメラ奮闘記
2012/08/18


「トランジスタ技術」という本があり、電子工作を仕事やら趣味にする人はよく見る雑誌なのである。
私は学生の頃(アマチュア無線をやっていた)とパソコンが普及しだした頃(オームが活動していた頃)はよく見ていたのだが、最近は本屋で表紙を見るだけだった。

それが今年2012年3月号で、「チョコっとカメラ」という特集があり、安いCMOSセンサーを使って映像を取り込む記事が出た。

それを見て「コリャ面白そうだ!!」と、衝動的に買い込んでしまったのだが、本格的な電子工作なんて大学生の頃以来30年以上やっていないし、PICとかいうワンチップマイコンは初めて使うし、Cでのプログラミングは仕事でやったにしても15年くらいも前の話で完璧に忘れているし、なによりも60歳近くなって頭もぼけてきておりエライ苦労をしてしまった。

とりあえず、カメラからPICを通じてUSBを使ってパソコンに映像を取り込んで表示するまでが通ったので、私自信が忘れないように記録しておこうと思う。



「トランジスタ技術」の特集では二種類のカメラが紹介されており、一つはCCDとレンズ、そして制御用のICが一体になったカメラAと称するもの、もう一つはそのカメラA(OV7670)に一画面分の画像メモリを搭載したカメラB(OV7670+FIFO)と称するものである。

私の計画では、安いPICというワンチップマイコンを使用し、テストを繰り返しながらパソコンに画像を取り込みたかった。
そこで、一画面をメモリに取り込んだらパソコンとUSBの速度に合わせて画像データを取り出せるカメラBを使用することにした。

photo317.JPG これが特集で出ていたカメラBで、雑誌を買ってすぐに申し込めば1980円で買えたのに、私はボケッとしていて購入が5月近くなってしまい2980円で手に入れた。
日昇テクノロジーという会社なのだが、だいぶ売れているらしく半年経った今でも売り上げナンバーワンになっていた。
http://www.csun.co.jp/
photo318.JPG ブレッドボードに刺したPIC18F4550で、40ピンのワンチップマイコンである。
USBでパソコンと通信が可能になっている。
ナント!これが370円くらいで手に入る。
上に写っているUSBのコネクターの方が高かったンじゃないだろうか?

配線がヘタクソで汚いのがちょっと恥ずかしいのだが、ご勘弁願いたい。
photo319.JPG これがPICKit3というワンチップマイコンにプログラムを書き込む機械。
ICのアダプターと合わせて6000円くらいだった。

これらは全て秋月電子の通販で揃えた。
秋葉原に行くのも楽しいのだが、正直言って部品を探すのもしんどい感じで、電車賃を考えれば通販でも良いじゃん?という感覚である。
http://akizukidenshi.com/catalog/default.aspx

この写真がカメラとマイコンで、右下にカメラ、その左にいくつかのLEDが状態を表示しており、左が40ピンのPIC18F4550。
上がUSBのコネクターでパソコンに繋がる。
電源はUSBの5Vを3端子レギュレーターで3Vに落として供給している。

photo320.JPG

下の写真が全景で、カメラではちょうどウエットティッシュのボトルを写しており、パソコンにその画像が映っている。
パソコンで表示している画像は480×360画素で、カメラBのメモリの容量の関係で680×480が出来なかった。

オマケにUSB通信が遅くて、一画面を送信するのに10秒以上かかる。
これでは動画じゃなくてただの連続写真である。
速度向上が最大の課題となってしまった。
まぁ、USB通信は一番サンプルが手ごろなのを使ってしまったので、もうちょっと勉強しようと思う。

photo321.JPG

下の写真がパソコンの画像で、今回ソフトの開発はPIC側がマイクロチップ社のMPLABとC18コンパイラ、パソコン側はマイクロソフトのVC++2010を使用した。
http://www.microchip.co.jp/
http://www.microsoft.com/ja-jp/dev/express/default.aspx
USB通信のサンプルはPICを出しているマイクロチップ社のHPからダウンロードした。
カメラとの通信のSCCBのサンプルはトランジスタ技術のHPからダウンロードした。
http://toragi.cqpub.co.jp/

全て無償のソフトで出来てしまったのがビックリで、なんだかちょっと不安なくらいである。
もっともSCCBのソフトはコンパイラーが違ったせいか動かなかったのでちょっと改造した。

photo322.JPG

私が作った回路とソフトは、あまりにもテスト用のものがセンス悪く残っているので、もうちょっと整理してから公開するつもりです。

しかしVC++はなんでこんなになってしまったのでしょうか?
フォームの中にコーディングするなんて、私のような古い人間からすると「おぞましい」という感覚になってしまいます。
以前のドキュメントクラス〜ビュークラスが一番良いとは思いませんが、「いくらなんでもあんまりだ!!」という感覚です。


2012/09/05

チョコっとカメラから画像をPICで取り込む回路を整理しようと思ったら、一ヶ月も経つともう記憶がアヤフヤになってしまい、我ながら「なんでこんな回路にしたのだろう?」と、誰かに聞きたくなってしまうのもある。
そこで、とりあえず今の回路を残しておくことにした。

確かに、初めてPICというマイコンを使うので、テストというか試しで作りこんだ部分が多々あるのである。
とりあえず覚えているかぎりの情報を出しておくことにする。

1、カメラはOV7670というもので、それにFIFOという画像記録用のメモリが付いている。

このFIFOは393,216BYTESのメモリであり、今回のようにRGBで一画素に2BYTES使うと有効なのは196608画素となる。
カメラのOV7670は640×480をサポートしているのだが、それだと画素数が326400となり、全然足りない。
縦横比を4/3でやろうとすると、480×360がきりのよい数字では最大になるのである。

2、PIC18F4550を選んだのは以下の理由。

・カメラのモジュールと同じ3.3Vで動作可能。
・USBの通信が可能。
・I/Oが沢山付いていて、私のような初心者にはテストがしやすそうだった。
・けっこうな高速動作が可能。

秋月ではUSBのコネクターが付いてすぐパソコンと繋げられるものもあって魅力的だったのだが、5V動作となっており、カメラが3.3Vなので繋げるのが大変そうだったのでバラバラな部品から組み立てた。

3、回路図は以下のとおりで、やたらにLEDがアチコチについている。
これは作っている最中はいろいろ実験しながら作ったので、プログラムのテスト時に意図したルートを通っているかLEDの発光で試験したものである。
ポートDは全てLEDの出力になっているのだが、USB通信のサンプルでLEDをいくつか使ったのが発端なので、LEDはポートCに移動させたい。
回路図

4、回路の意図。

・PICのRA1とカメラのSDAに100Ωが入っているが、これはSCCB通信で双方向(場合によってはカメラからIC、場合によってはPICからカメラ)に信号が流れるので、タイミングによっては出力モード同士が競合し、ICが破壊される場合を想定して入れてある。
(片方がローの出力、片方がハイの出力となるとショート状態になる)

・RA1に入っている15Kのプルアップ抵抗は、おそらく不要だと思われる。
先ほど外して試験してみたが、問題なくカメラとSCCB通信は動作している。

・カメラのVSYNCがPICのRA2とRB0に入っている理由は、当初RA2で処理していたが、途中でVSYNCの信号で割り込み処理をしなければならなくなり、しかも割り込み処理はRBのポートでしか出来なかったので追加した。

・上記の理由で、カメラからのデータをBポートで入力しようとしたのにRB0が割り込みで取られてしまい、RB1〜RB7の7ビットになってしまい、急遽EポートのRE2を1ビット使用した。
そのせいで、ポートBからデータを8ビット一回でゲットするプログラムが、ポートBからは7ビット、ポートEから1ビットゲットして合成して8ビットにするという美しくないプログラムになってしまった。


2012/09/16
回路を若干変更して、ちょっとだけスッキリした。
変更点としては・・・・

1、カメラからPICへデータを取り込むポートをBからDに変更した。
これによってポートBから7ビット、ポートEから1ビットという変則的な入力をポートDだけで一回でゲットできるようになった。

2、LEDを点灯させていたポートDはCに変更した。
現在はBポートがいくつか空いている状態である。

新回路図


2012/10/19
カメラのボードをブレッドボードからユニバーサルボードに変更して顕微鏡にセットしてみた。

私はコンピュータのプログラムを作るのや、電子回路を作るのは、まぁ自分で言うのもなんだがそれなりに出来ると思っているのだが、どうも機械工作の腕はイマイチで、これを作るだけでかなりの時間と手間と、それなりの失敗した部品がパーになった。

だいぶアヤシイ感じだが、なんとか顕微鏡の接眼レンズにカメラを取り付けて画像を取り込むことができた。
顕微鏡は10年以上前、母親が不燃物の回収日にゴミ捨て場から拾ってきたもので、今回ようやく役に立った。

この顕微鏡は大正洋行という会社が出していたもので、「TSCO顕微鏡、No-106」というもので、おそらく昭和45年前後のものだと思われる。
ちゃんとした木の箱に入っており、解剖セットもついた当時としては高級品のようである。

photo338.JPG

写っているのは竹の茎の断面で、倍率は100倍である。
当初はハンディータイプの携帯顕微鏡にカメラをセットしようとしていたのだが、やってみると、子供の学習用にせよちゃんとした顕微鏡の方が断然画質が良いのでこちらにしてみた。

photo339.JPG


2013/01/13

10月に更新してから、ちょっと停滞していた。
USB通信のスピードアップを画策して、色々実験していたのだが、どうもうまくいかない。
だんだん飽きてきてしまって、途中でモーターのコントロールだとか、温度センサーやら気圧センサーで気象ロガーを作ったり、寄り道を始める始末だった。

そんなこんなしているうちに、ある人から「PIC18F4550とOV7670を使って、同じようなことをやってみたがうまくいかない。プログラムを見せてくれ」というリクエストが来た。

プログラムがあまりにも汚いので、ちょっと躊躇するのだが、困っている人がいるなら恥を忍んで公開しましょうという気になった。
「こんなんで良かったらどうぞ」という気分である。
ただ、元になったプログラムは「トラ技」のサイトのものなので、商売で使用するのにはコピーライトが必要だと思う。

まずは、PICのMPLABの状態。

camAtest.c----プログラム本体
sccb.c--------カメラとの通信ルーチンのプログラム
sccb.h--------通信プログラムのヘッダーファイル
HardwareProfile.h--------USB通信のヘッダーファイル

上記4ファイルが私が変更したもので、その他usb_xxというファイルは全てマイクロチップ社のHPからダウンロードしたものをそのまま使用しているので、そちらを参照して頂きたい。
また、camA.hは何時の間にかカラッポになってしまって、使用していない。

MPLAB001.jpg

HardwareProfile.hの中は、先頭から33行までは何も変更なし。
34-35行目は、サンプルでは40MHzで動作させていたのを48MHz動作に変更しているのだが、実際に本当に48MHzで動作しているのかイマイチ不安な状況なのである。
特に問題無さそうなので、これでやっている。


#ifndef HARDWARE_PROFILE_LOW_PIN_COUNT_USB_DEVELOPMENT_KIT_H
#define HARDWARE_PROFILE_LOW_PIN_COUNT_USB_DEVELOPMENT_KIT_H

    /*******************************************************************/
    /******** USB stack hardware selection options *********************/
    /*******************************************************************/
    //This section is the set of definitions required by the MCHPFSUSB
    //  framework.  These definitions tell the firmware what mode it is
    //  running in, and where it can find the results to some information
    //  that the stack needs.
    //These definitions are required by every application developed with
    //  this revision of the MCHPFSUSB framework.  Please review each
    //  option carefully and determine which options are desired/required
    //  for your application.

    //#define USE_SELF_POWER_SENSE_IO	
    #define tris_self_power     TRISAbits.TRISA2    // Input
    #if defined(USE_SELF_POWER_SENSE_IO)
    #define self_power          PORTAbits.RA2
    #else
    #define self_power          1
    #endif

    //#define USE_USB_BUS_SENSE_IO
    #define tris_usb_bus_sense  TRISAbits.TRISA1    // Input
    #if defined(USE_USB_BUS_SENSE_IO)
    #define USB_BUS_SENSE       PORTAbits.RA1
    #else
    #define USB_BUS_SENSE       1
    #endif

    #define DEMO_BOARD LOW_PIN_COUNT_USB_DEVELOPMENT_KIT
    #define LOW_PIN_COUNT_USB_DEVELOPMENT_KIT
    #define CLOCK_FREQ 48000000
//    #define CLOCK_FREQ 40000000
    
    /** LED ************************************************************/
//    #define mInitAllLEDs()      LATC &= 0xF0; TRISC &= 0xF0;
//    #define mInitAllLEDs()      LATD &= 0x00; TRISD &= 0x00;
    
    #define mLED_1              LATCbits.LATC0
    #define mLED_2              LATCbits.LATC1
    #define mLED_3              LATCbits.LATC2
    #define mLED_4              LATCbits.LATC6
    #define mLED_5              LATCbits.LATC7
//    #define mLED_6              LATDbits.LATD5
    #define mLED_7              LATEbits.LATE2
//    #define mLED_8              LATDbits.LATD7

    /** CAM ************************************************************/
    #define Cam_WEN				LATAbits.LATA4		// Write Enable
    #define Cam_RRST            LATAbits.LATA5		// Read Reset
    #define Cam_OE	            LATEbits.LATE0
    #define Cam_RCLK	        LATEbits.LATE1
//	#define Cam_data0			PORTEbits.RE2

#endif  //HARDWARE_PROFILE_LOW_PIN_COUNT_USB_DEVELOPMENT_KIT_H

sccb.hは、カメラとPICの通信のためのプログラムのヘッダーファイルで、この中で重要なのがTRISSDAで、ポートAのビット1を入力にしたり出力にしたり変更する。


/********************************
*  SCCB用ヘッダファイル
********************************/

//#define _XTAL_FREQ  20000000	// クロック周波数設定 12MHz

#define	SDA		LATAbits.LATA1
#define	SCL		LATAbits.LATA0
#define TRISSDA	TRISAbits.TRISA1
#define SDIN	PORTAbits.RA1

void I2CStart(void);
void I2CStop(void);
void I2COut(unsigned char data);
unsigned char I2CIn(void);

sccb.cは、カメラとPICとの通信ルーチンで、このプログラムは時間を取って順次説明を載せようと思います。
特に「カメラの初期設定」の部分は、英文のマニュアルを見ながらアーデモナイ・コーデモナイと苦労した部分です。


/*********************************************
*  SCCB制御ルーチン
*  Compiler:C18
*  PIC18F4550 48MHz
**********************************************/
//#include 
#include "delays.h"
#include "sccb.h"
#include "HardwareProfile.h"
#include "Compiler.h"
//#include "camA.h"

// プロトタイプ宣言
void wait(void);

/*****************************
* SCCBスタート条件
*****************************/
void I2CStart(void)
{
	/* SCL,SDAは常時Highとする */
	SDA = 0;				// 先にSDA Low
	wait();
	TRISSDA = 0;				// SDA出力
}
/*****************************
* SCCBストップ条件
*****************************/
void I2CStop(void)
{
	SCL = 0;				// SCL Low
	wait();
	SDA = 0;				// SDA Low
	TRISSDA = 0;				// 出力モードに戻す SDA =Low
	wait();
	SCL = 1;				// 先にSCLをHigh
	wait();
	SDA = 1;				// 後からSDAをHigh
}

/****************************
* SCCBで1バイト出力 
****************************/
void I2COut(unsigned char data)
{
	int i;
	unsigned char BitPos;

	/* Data Out */
	TRISSDA = 0;				// SDA出力モード
	BitPos = 0x80;				// ビット位置初期値
	for(i=0; i<8; i++)			// 8ビット繰り返し
	{
		SCL = 0;			// SCL Low
		wait();
		if((data & BitPos) != 0)	// ビット出力
			SDA = 1;		// SDA High
		else
			SDA = 0;		// SDA Low
		BitPos = BitPos >> 1;		// ビット位置移動
		wait();
		SCL = 1;			// SCL Highに戻す
	}
	/* dummy ACK */
	wait();
	SCL = 0;					// クロック1Low
	TRISSDA = 1;				// 入力モードにしてACK入力
	wait();
	SCL = 1;				// クロックHighに戻す
	wait();					// add
	return;
}

/****************************
* SCCBで1バイト入力 
****************************/
unsigned char I2CIn(void)
{
	int i;
	unsigned char BitPos;
	unsigned char data=0;

	/* Data In */
	TRISSDA = 1;					// SDA入力モード
	BitPos = 0x80;					// ビット位置初期値
	for(i=0; i<8; i++)				// 8ビット繰り返し
	{
		SCL = 0;				// SCL Low
		wait();
		SCL = 1;				// SCL Highに戻す
		wait();
		if(SDIN != 0)				// ビット入力
			data = data | BitPos;	
		BitPos = BitPos >> 1;		// ビット位置移動
	}
	/* dummy ACK */
	wait();
	SCL = 0;					// クロック1Low
	TRISSDA = 1;					// 入力モードにしてACK入力
	wait();
	SCL = 1;					// クロックHighに戻す
	wait();		// add
	return(data);					// データを戻り値とする
}

/*********************************
* カメラへデータ出力
*********************************/
void cam_data(unsigned char adrs, unsigned char data)
{
	I2CStart();					// スタート
	I2COut(0x42);				// スレーブアドレス
	I2COut(adrs);				// レジスタアドレス
	I2COut(data);				// データ出力
	I2CStop();					// ストップ
//	__delay_us(30);				// 遅延
	Delay10TCYx(30);	// clk = 48M 1inst=4clk 12M/inst
						// 25us*12M->300
}

/*********************************
* カメラからデータ読み込み
*********************************/
unsigned char cam_read(unsigned char adrs)
{
	unsigned char data;
	I2CStart();					// スタート
	I2COut(0x42);				// スレーブアドレス(w)
	I2COut(adrs);				// レジスタアドレス	
	I2CStop();					// 一旦終わる
//	__delay_us(30);
	Delay10TCYx(30);	// clk = 48M 1inst=4clk 12M/inst
						// 25us*12M->300

	I2CStart();					// 通信再開
	I2COut(0x43);				// スレーブアドレス(r)
//	Delay10TCYx(30);	// clk = 40M 1inst=4clk 10M/inst
	data = I2CIn();				// データ入力
	I2CStop();					// ストップ
//	__delay_us(30);
	Delay10TCYx(30);	// clk = 48M 1inst=4clk 12M/inst
						// 25us*12M->300
	return(data);
}

/*********************************
* カメラの初期設定
*********************************/
void cam_init(){
	cam_data(0x12, 0x80);
//	delay_100ms(2);
	Delay10KTCYx(100);	// clk = 48M 1inst=4clk 12M/inst
						// 83.333ms->83333us*12M->1000000
	cam_data(0x12, 0x04);		//	COM7 RGB カラーバー
	cam_data(0x40, 0xD0);		//	COM15
	cam_data(0x8C, 0x02);		//	RGB444

	cam_data(0x15, 0x02);		//	VSYNC 逆転

	cam_data(0x1E, 0x31);		//	Mirror Image V and H

	cam_data(0x17, 0x1B);		//	HSTART
	cam_data(0x18, 0x57);		//	HSTOP
	cam_data(0x19, 0x12);		//	VSTART
	cam_data(0x1A, 0x6C);		//	VSOP

//	cam_data(0x03, 0x0A);		//	VREF
//	cam_data(0x32, 0x80);		//	HREF
//	cam_data(0x0C, 0x00);		//	COM3 defauld value

	cam_data(0x3A, 0x04);		//	TSLB
	cam_data(0x3B, 0x0A);		//	COM11 50Hz
//	cam_data(0x3E, 0x19);		//	COM14
//	cam_data(0x70, 0x3A);		//	SCALING_XSC
//	cam_data(0x71, 0x35);		//	SCALING_YSC
//	cam_data(0x72, 0x11);		//	SCALING_DCWCTR
//	cam_data(0x73, 0xF1);		//	SCALING_PCLK_DIV
//	cam_data(0xA2, 0x02);		//	SCALING_PCLK_DELAY

	cam_data(0x4F, 0x80);		//	色の濃さ MTX1
	cam_data(0x50, 0x80);		//	色の濃さ MTX2
	cam_data(0x51, 0x00);		//	色の濃さ MTX3
	cam_data(0x52, 0x22);		//	色の濃さ MTX4
	cam_data(0x53, 0x5E);		//	色の濃さ MTX5
	cam_data(0x54, 0x80);		//	色の濃さ MTX6
	cam_data(0x56, 0x40);		//	def
	cam_data(0x58, 0x9E);		//	色の濃さ MTXS

	cam_data(0x59,0x88);
	cam_data(0x5a,0x88);
	cam_data(0x5b,0x44);
	cam_data(0x5c,0x67);
	cam_data(0x5d,0x49);
	cam_data(0x5e,0x0e);
	cam_data(0x69,0x00);
	cam_data(0x6a,0x40);
	cam_data(0x6b,0x0a);
	cam_data(0x6c,0x0a);
	cam_data(0x6d,0x55);
	cam_data(0x6e,0x11);
	cam_data(0x6f,0x9f);
	cam_data(0xb0,0x84);

	cam_data(0x11, 0x8F);			//	BF->2.14s
						//	AF->1.6s
						//	9F->1.08s
						//	8F->0.53s
}


/******************************
*  100msec遅延関数
******************************/
void delay_100ms(unsigned int time)
{
	time *= 4;				// 4倍
	while(time){
//		__delay_ms(25);			// 25msec
	Delay10KTCYx(30);	// clk = 48M 1inst=4clk 12M/inst
						// 25ms*12M->300000
		time--;				// 100msec x time
	}
}

void wait(){
//	__delay_us(2);
	Delay10TCYx(2);		// clk = 48M 1 inst=4clk 12M/inst
						// 1.666us*12M->20
}

これが本体のcamAtest.cで、相当ゴチャゴチャしてしまって、もうちょっと整理しないと判りづらい。
なにぶん、USBの通信とユーザーインターフェイス、そしてカメラとのデータのやり取りが一つのプログラムになっています。

特にUSB通信はバイナリでデータを送りたいのと簡単だったので、HIDクラスを使用しています。
そのせいでデータを64バイトずつ細切れにパソコンに送ることになり、これもまたプログラムが複雑になる原因になっています。
MSDクラスにすれば解決するかもしれませんが、どうも不勉強なので、まだよく判りません。

時間をみつけて、プログラムの説明をしていきます。


/********************************************************************
*  PIC18F4550を使用したカメラデータ取得
*  OV7670+FIFO
*  USB Demo を使用
********************************************************************/
/** ファイルインクルード **************************/
#include "./USB/usb.h"
#include "HardwareProfile.h"
#include "./USB/usb_function_hid.h"

//
//	カメラ関係
//
//#include "camA.h"
#include "delays.h"

/** コンフィギュレーション ***********************/
        #pragma config PLLDIV   = 5         // (20 MHz crystal on PICDEM FS USB board)
//        #pragma config PLLDIV   = 3         // (12 MHz crystal on PICDEM FS USB board)
        #pragma config CPUDIV   = OSC1_PLL2   
        #pragma config USBDIV   = 2         // Clock source from 96MHz PLL/2
        #pragma config FOSC     = HSPLL_HS
        #pragma config FCMEN    = OFF
        #pragma config IESO     = OFF
        #pragma config PWRT     = OFF
        #pragma config BOR      = ON
        #pragma config BORV     = 3
        #pragma config VREGEN   = ON      //USB Voltage Regulator
        #pragma config WDT      = OFF
        #pragma config WDTPS    = 32768
        #pragma config MCLRE    = ON
        #pragma config LPT1OSC  = OFF
        #pragma config PBADEN   = OFF
//      #pragma config CCP2MX   = ON
        #pragma config STVREN   = ON
        #pragma config LVP      = OFF
//      #pragma config ICPRT    = OFF       // Dedicated In-Circuit Debug/Programming
        #pragma config XINST    = OFF       // Extended Instruction Set
        #pragma config CP0      = OFF
        #pragma config CP1      = OFF
//      #pragma config CP2      = OFF
//      #pragma config CP3      = OFF
        #pragma config CPB      = OFF
//      #pragma config CPD      = OFF
        #pragma config WRT0     = OFF
        #pragma config WRT1     = OFF
//      #pragma config WRT2     = OFF
//      #pragma config WRT3     = OFF
        #pragma config WRTB     = OFF       // Boot Block Write Protection
        #pragma config WRTC     = OFF
//      #pragma config WRTD     = OFF
        #pragma config EBTR0    = OFF
        #pragma config EBTR1    = OFF
//      #pragma config EBTR2    = OFF
//      #pragma config EBTR3    = OFF
        #pragma config EBTRB    = OFF

/******** USB関連バッファ、変数定義 ****/
#pragma udata USB_VARIABLES=0x500
unsigned char ReceivedDataBuffer[64];
unsigned char SendBuf[64];
#pragma udata
USB_HANDLE USBOutHandle = 0;
USB_HANDLE USBInHandle = 0;
//BOOL blinkStatusValid = TRUE;
unsigned int	mLED_count;

/**** グローバル変数定義 ***/
//BYTE  counter;
//BOOL  blinkStatusValid;

//
//	カメラ関係
//
unsigned char camdata;
//BOOL	flg_VSink;
//BOOL	flg_Hsink;
//int		count_H;
//int		max_count_H;
BOOL	cam_write_req;
BOOL	cam_write_busy;
BOOL	cam_write_fin;

/*** コマンド定数定義 ***/
typedef enum
{
    CHECK	= 0x30,
	POUT	= 0x31,
	CIN		= 0x32,
	COUT	= 0x33,
	CCHK	= 0x34,
	CEXE	= 0x35,
    RESET	= 0xFF

}TYPE_CMD;

/** 関数プロトタイピング ****************************/
void BlinkUSBStatus(void);
void ProcessIO(void);
void YourHighPriorityISRCode();
void YourLowPriorityISRCode();
void USBCBSendResume(void);
void EXT0Int(void);
void wait(void);

//
//	カメラ関係	
//
void cam_init(void);
unsigned char cam_read(unsigned char);
void cam_data(unsigned char, unsigned char);
void delay_100ms(unsigned int);
void wait(void);

/************ 割り込みベクタ定義 ***********/
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = 0x08
void Remapped_High_ISR (void)
{
     _asm goto YourHighPriorityISRCode _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = 0x18
void Remapped_Low_ISR (void)
{
     _asm goto YourLowPriorityISRCode _endasm
}
	
/************* 割り込み処理関数 ************/
#pragma code
#pragma interrupt YourHighPriorityISRCode
void YourHighPriorityISRCode()
{
	if ((INTCONbits.INT0IE == 1) && (INTCONbits.INT0IF == 1))
		{
			EXT0Int();
		}
        USBDeviceTasks();
}
#pragma interruptlow YourLowPriorityISRCode
void YourLowPriorityISRCode()
{
}

/***********  メイン関数 ***************************/
#pragma code
void main(void)
{   
//  IOピン初期設定
	PORTA = 0b00000011;			//I2C initial
	TRISA = 0b11001100;			//PORTA=0,1,4,5 output   2,3 INPUT
	TRISB = 0b11111111;			//PORTB=0-7 Input
	TRISE = 0b00000000;			//PORTE=0,1,2 output
	TRISC = 0b00000000;			//PORTC=0,1,2,6,7 output
	TRISD = 0b11111111;			//PORTD=0-7 Input
	
	CMCON = 0x07;				// コンパレータオフ
//	SPPCON = 0x00;				// high-speed USB PORT Disable				

//	TRISA = 0xFF;					// RA0-5入力
//	TRISB = 0x7F;					// RB7(TX)以外すべて入力
//	LATC = 0;						// 出力初期化
//	TRISC = 0xF0;					// RC6,7アナログ入力、RC0-3出力
	/* ADC初期化 */
	ADCON0 = 0;						// 停止
	ADCON1 = 0x0F;					// Digital I/O
//	ADCON2 = 0xBE;					// 右詰め,20Tad,Fosc/64

//	LATE = 0;						// 初期化

	/* USB関連 **/
	USBDeviceInit();				// USB初期化	
	USBInHandle = 0;	
	USBOutHandle = 0;
	USBDeviceAttach();				// USB割り込み有効化
	mLED_count = 0;

	//
	// カメラ
	//
//	max_count_H = 0;
//	count_H = 0;
	cam_init();					//カメラ初期設定
	cam_write_req = FALSE;
	cam_write_busy = FALSE;
	cam_write_fin = FALSE;
	
	Cam_RRST = 1;				// Read Reset
	Cam_OE = 1;					// Output Enable

	/* port B */
	INTCON2bits.INTEDG0 = 0;		// Falling Edge
	INTCONbits.INT0IE = 1;			// INT0 Enable
	INTCONbits.PEIE = 1;

	/*********** メインループ ***************/
    while(1)
    {
//		mLED_8 = 1;
//		mLED_8 = 0;
//		mLED_8 = 1;
//		mLED_8 = 0;
//		mLED_8 = 1;
//		mLED_8 = 0;
//		Delay10TCYx(1);	// clk = 48M 1 inst=4clk 12M/inst
						// 0.83333us
//		mLED_8 = 1;
//		Delay10TCYx(2);	// clk = 48M 1 inst=4clk 12M/inst
						// 1.6666us
//		mLED_8 = 0;

//		camdata = cam_read(0x0F);
//		if (camdata == 0xFF) mLED_7 = 1;
//		else mLED_7 = 0;
//		if (Cam_data0==1) mLED_7 = 1;
//		else mLED_7 = 0;

//		Delay10KTCYx(1);	// clk = 40M 1 inst=4clk 10M/inst

		/** USB目印LED点滅 **/
		BlinkUSBStatus();		// LED点滅実行
			
		/*** USB接続中なら送受信実行 ***/
		if((USBDeviceState >= CONFIGURED_STATE)&&(USBSuspendControl!=1))
			ProcessIO();				// コマンド実行
	}
}

/***************************************************
 * ユーザーアプリの入出力処理関数
 * USBからのコマンドにより機能実行
 ***************************************************/
void ProcessIO(void)
{
	unsigned char int_c0;
	unsigned char int_c1;
	int h_line;
	int	v_line;
	int	ix_buf;
	int ix_max;

	/***** データ受信処理 ******/
	if(!HIDRxHandleBusy(USBOutHandle))
	{ 
		SendBuf[0] = ReceivedDataBuffer[0];
		SendBuf[1] = ReceivedDataBuffer[1];			       
		SendBuf[2] = ReceivedDataBuffer[2];			       
		SendBuf[3] = ReceivedDataBuffer[3];			       
		/******** コマンドの処理 ********/
		switch(ReceivedDataBuffer[0])		// コマンドコードチェック
		{
			/** 接続確認応答 **/
			case CHECK:
				SendBuf[2] = 'O';
				SendBuf[3] = 'K';
				if(!HIDTxHandleBusy(USBInHandle))
					USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&SendBuf[0],64);
				break;
			/** 出力ピン出力要求と状態応答の場合 ***/
			case POUT:		// LED 点灯
				if(ReceivedDataBuffer[1] == 0x31)
				{
					if(ReceivedDataBuffer[2] == 0x31)
					{
						mLED_5 = 1;
						SendBuf[2] = 0x31;
					}
					else if(ReceivedDataBuffer[2] == 0x30)
					{
						mLED_5 = 0;
						SendBuf[2] = 0x30;
					}
				}
				if(!HIDTxHandleBusy(USBInHandle))
					USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&SendBuf[0],64);
				break;
			/** 入力ピン状態要求と応答の場合  **/	
			case CIN :		// get cam data
				if(ReceivedDataBuffer[1] == 0x31){
					SendBuf[3] = cam_read(ReceivedDataBuffer[2]);
//					SendBuf[3] = 0xab;
				}
				else
				{
					SendBuf[3] = 0xFF;
				}
//				else if(ReceivedDataBuffer[1] == 0x32){
//					if(sw2)
//						SendBuf[2] = 0x31;
//					else
//						SendBuf[2] = 0x30;					
//				}
//				else if(ReceivedDataBuffer[1] == 0x33){
//					if(sw3)
//						SendBuf[2] = 0x31;
//					else
//						SendBuf[2] = 0x30;
//				}
				if(!HIDTxHandleBusy(USBInHandle))
					USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&SendBuf[0],64);
				break;
			/***** カメラデータ書き込み *****/
			case COUT:
				if(ReceivedDataBuffer[1] == 0x31)
				{
					cam_data(ReceivedDataBuffer[2], ReceivedDataBuffer[3]);
					SendBuf[3] = cam_read(ReceivedDataBuffer[2]);
				}
				else
				{
					SendBuf[3] = 0xFF;
				}
				if(!HIDTxHandleBusy(USBInHandle))
					USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&SendBuf[0],64);
				break;
			/***** CPU CHECK *****/
			case CCHK:
				if(ReceivedDataBuffer[1] == 0x31)
				{
					//cam_data(ReceivedDataBuffer[2], ReceivedDataBuffer[3]);
//					max_count_H = 1024;
//					int_c0 = max_count_H / 256;
//					int_c1 = max_count_H - ( int_c0 * 256 ); 
					SendBuf[2] = int_c0;
					SendBuf[3] = int_c1;
				}
				else
				{
					SendBuf[3] = 0xFF;
				}
				if(!HIDTxHandleBusy(USBInHandle))
					USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&SendBuf[0],64);
				break;
			/***** CPU EXEC *****/
			case CEXE:
				if(ReceivedDataBuffer[1] == 0x31)	// カメラへ画像取込
				{
					cam_write_req = TRUE;
					cam_write_fin = FALSE;
				}
				else if(ReceivedDataBuffer[1] == 0x33)	// FIFOから画像取出
				{
					mLED_7 = 1;
					// ReceivedDataBuffer[2] == 0x00 first
					// ReceivedDataBuffer[2] == 0x01 continue
					// ReceivedDataBuffer[2] == 0x02 last
					if (ReceivedDataBuffer[2] == 0x00)	// readカウンタリセット
					{
						// cam reset
						Cam_OE = 0;		// Output Enable  Active low
						wait();
						Cam_RRST = 0;		// Reset Read Address
						wait();
						Cam_RCLK = 1;
						wait();
						Cam_RCLK = 0;
						wait();
						Cam_RCLK = 1;
						wait();
						Cam_RCLK = 0;
						wait();
						Cam_RRST = 1;
					}
					Cam_OE = 0;		// Output Enable  Active low
					wait();

					if (ReceivedDataBuffer[2] == 0x02) ix_max = 35;	// 32+3
					else ix_max = 61;		//  58+3

					for ( ix_buf = 3; ix_buf < ix_max; ix_buf++ )
					{
						Cam_RCLK = 1;
						Delay1TCY();	// clk = 48M 1 inst=4clk 12M/inst
								// 0.08us*12M->1
								// Real Value 0.2us
//						wait();				2012/09/27
						Cam_RCLK = 0;
//						wait();				2012/09/27
						SendBuf[ix_buf] = PORTD;
//						if (Cam_data0 == 0) SendBuf[ix_buf] &= 0xFE;
//						else SendBuf[ix_buf] |= 0x01;
					}

					Cam_OE = 1;
//					mLED_7 = 0;
				}	// FIFOから画像取出
				if(!HIDTxHandleBusy(USBInHandle))
					USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&SendBuf[0],64);
				mLED_7 = 0;
				break;
			/** リセットデバイス ***/
			case RESET:
				Reset();
				break;
			/*** 不明 ****/
			default:
				break;
		}
		/* 次の受信実行 */
		USBOutHandle = HIDRxPacket(HID_EP,(BYTE*)&ReceivedDataBuffer,64);
	}
}

/****************************************************
 * USB状態表示用LEDブリンク処理関数
 *  USBアタッチ:高速ブリンク
 *  SUB接続完了:低速ブリンク
 ***************************************************/
void BlinkUSBStatus(void)
{
	mLED_count++;
	if(mLED_count > 32000)
	{
		mLED_1 = 0;
		mLED_2 = 0;
		mLED_3 = 0;
		mLED_4 = 0;
		if(mLED_count > 64000) 	mLED_count = 0;	
	}
	else		// mLED_count <= 10000
	{

		if(USBSuspendControl == 1)
		{
			mLED_1 = 1;
			mLED_2 = 0;
			mLED_3 = 0;
			mLED_4 = 0;
		}
		else
		{
			if(USBDeviceState == DETACHED_STATE)
			{
				mLED_1 = 0;
				mLED_2 = 1;
				mLED_3 = 0;
				mLED_4 = 0;
			}
			else if(USBDeviceState == ATTACHED_STATE)
			{
				mLED_1 = 1;
				mLED_2 = 1;
				mLED_3 = 0;
				mLED_4 = 0;
			}
			else if(USBDeviceState == POWERED_STATE)
			{
				mLED_1 = 0;
				mLED_2 = 0;
				mLED_3 = 1;
				mLED_4 = 0;
			}
			else if(USBDeviceState == DEFAULT_STATE)
			{
				mLED_1 = 1;
				mLED_2 = 0;
				mLED_3 = 1;
				mLED_4 = 0;
			}
			else if(USBDeviceState == ADDRESS_STATE)
			{
				mLED_1 = 0;
				mLED_2 = 1;
				mLED_3 = 1;
				mLED_4 = 0;
			}
			else if(USBDeviceState == CONFIGURED_STATE)
			{
				mLED_1 = 1;
				mLED_2 = 1;
				mLED_3 = 1;
				mLED_4 = 0;
			}
			else
			{
				mLED_1 = 0;
				mLED_2 = 0;
				mLED_3 = 0;
				mLED_4 = 1;
			}
		}

	}	//	mLED_count > 10000
}

/******************************************************************
************** USB Callback Functions *****************************
*******************************************************************/
/******************************************************************
 * Function:        void USBCBSuspend(void)
 ******************************************************************/
void USBCBSuspend(void)
{
}
/*******************************************************************
 * Function:        void USBCBWakeFromSuspend(void)
 *******************************************************************/
void USBCBWakeFromSuspend(void)
{
}
/********************************************************************
 * Function:        void USBCB_SOF_Handler(void)
 *******************************************************************/
void USBCB_SOF_Handler(void)
{
}
/*******************************************************************
 * Function:        void USBCBErrorHandler(void)
 *******************************************************************/
void USBCBErrorHandler(void)
{
}
/*******************************************************************
 * Function:        void USBCBCheckOtherReq(void)
 *******************************************************************/
void USBCBCheckOtherReq(void)
{
	USBCheckHIDRequest();
}//end
/*******************************************************************
 * Function:        void USBCBStdSetDscHandler(void)
 *******************************************************************/
void USBCBStdSetDscHandler(void)
{
}//end
/*******************************************************************
 * Function:        void USBCBInitEP(void)
 *******************************************************************/
void USBCBInitEP(void)
{
    //enable the HID endpoint
    USBEnableEndpoint(HID_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
    //Re-arm the OUT endpoint for the next packet
    USBOutHandle = HIDRxPacket(HID_EP,(BYTE*)&ReceivedDataBuffer,64);
}
/*******************************************************************
 * Function:        void USBCBSendResume(void)
 ******************************************************************/
void USBCBSendResume(void)
{
    static WORD delay_count;

    if(USBGetRemoteWakeupStatus() == TRUE) 
    {
        //Verify that the USB bus is in fact suspended, before we send
        //remote wakeup signalling.
        if(USBIsBusSuspended() == TRUE)
        {
            USBMaskInterrupts();
            
            //Clock switch to settings consistent with normal USB operation.
            USBCBWakeFromSuspend();
            USBSuspendControl = 0; 
            USBBusIsSuspended = FALSE;  //So we don't execute this code again, 

            delay_count = 3600U;
            do
            {
                delay_count--;
            }while(delay_count);
            
            //Now drive the resume K-state signalling onto the USB bus.
            USBResumeControl = 1;       // Start RESUME signaling
            delay_count = 1800U;        // Set RESUME line for 1-13 ms
            do
            {
                delay_count--;
            }while(delay_count);
            USBResumeControl = 0;       //Finished driving resume signalling

            USBUnmaskInterrupts();
        }
    }
}
/*******************************************************************
 * Function:        BOOL USER_USB_CALLBACK_EVENT_HANDLER(
 *******************************************************************/
BOOL USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, WORD size)
{
    switch(event)
    {
        case EVENT_TRANSFER:
            break;
        case EVENT_SOF:
            USBCB_SOF_Handler();
            break;
        case EVENT_SUSPEND:
            USBCBSuspend();
            break;
        case EVENT_RESUME:
            USBCBWakeFromSuspend();
            break;
        case EVENT_CONFIGURED: 
            USBCBInitEP();
            break;
        case EVENT_SET_DESCRIPTOR:
            USBCBStdSetDscHandler();
            break;
        case EVENT_EP0_REQUEST:
            USBCBCheckOtherReq();
            break;
        case EVENT_BUS_ERROR:
            USBCBErrorHandler();
            break;
        case EVENT_TRANSFER_TERMINATED:

            break;
        default:
            break;
    }      
    return TRUE; 
}

//
//
//
void EXT0Int(void)
{
//	mLED_6 = 1;
//	mLED_6 = 0;
	INTCONbits.INT0IF = 0;		// Clear Interrupt Flag	
	if(cam_write_req)
	{
		Cam_WEN = 1;			// CAM Fifo Write Start 
		cam_write_busy = TRUE;	// 
		cam_write_req = FALSE;
	}
	else if(cam_write_busy)	
	{
		cam_write_busy = FALSE;	
		Cam_WEN = 0;			// CAM Fifo Write Finish
		cam_write_fin = TRUE;
		SendBuf[0] = 0x35;
		SendBuf[1] = 0x32;
		if(!HIDTxHandleBusy(USBInHandle))
			USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&SendBuf[0],64);
	}
}




2013/01/16

PICのプログラムだけでは、おそらくユーザーインターフェイスの部分がよく判らないと思うので、パソコンのプログラムも公開します。

まず、作成した画面は以下のようなもので、これは実物大です。
接続ボタンを押すと、USB通信がうまく行ってConnected OK!と出てきているところです。

次に、左のボックスに12(ヘキサ)を入れて、camReadを押したところで右の窓にカメラのアドレスが0x12であり、データが0x04だと表示されています。
これは、カメラからのデータがRGBで出力されることを意味します。

次に、その下のボックスに0x06を入れてcamWriteを押したところで、右の窓にアドレス0x12が0x06に変更されたことが出ています。
ここでもう一度上のcamReadを押すと、上の表示も0x06になりますが、まだ押していな状態です。

アドレス0x12を0x06にすると、下の画面のようにカメラはカラーバーを出力します。
ただし、カメラのレンズにカバーをして真っ暗にしないと、このようには出ません。

その下にヘキサ表示でデータが並んでいますが、これがカメラから送られたデータの一部をヘキサ表示したものです。

MPLAB002.jpg

この下がVC++のプログラムの一部です。
内容は・・・・作った私もだいぶ忘れているので、だんだん思い出したら書き出します。


	/************* グローバル変数定義 ********************/
	unsigned int ADCValue;
	DWORD BytesWritten = 0;
	DWORD BytesRead = 0;
	unsigned char OutputPacketBuffer[65];	//Allocate a memory buffer equal to our endpoint size + 1
	unsigned char InputPacketBuffer[65];

	BOOL read_ok;
	BOOL timer_get;

	/****************************************************/


	/// 
	/// Form1 の概要
	/// 
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: ここにコンストラクター コードを追加します
			//
			comboBox1->Items->Add( "Get Data1" );
			comboBox1->Items->Add( "Get Data2" );
			comboBox1->SelectedIndex = -1;

			//ピクチャボックスと同じ大きさのBitmapを作成
			Bitmap^ bmp = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height);
			pictureBox1->Image = bmp;

			read_ok = FALSE;
			timer_get = FALSE;

		}

上記のプログラムと、下記のプログラムの間には、自動で生成されたコードが沢山入っています。
下記の部分が、私が作成した本体です。


	private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
		/* Form閉じる */
		this->Close();
			 }

			 //
			 //		LED
			 //
	private: System::Void button3_Click(System::Object^  sender, System::EventArgs^  e) {
		OutputPacketBuffer[0] = 0;					// Report ID  
		OutputPacketBuffer[1] = 0x31;				// LED制御コマンド
		OutputPacketBuffer[2] = 0x31;				// LED1アドレス
		if(button3->BackColor  == Color::Green)
			OutputPacketBuffer[3] = 0x31;			// On制御
		else
			OutputPacketBuffer[3] = 0x30;			// Off制御
		/* コマンド送信 */
		WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0);
		/* 状態送信要求 */
		ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0);
		/* 状態色変更 */
		if(InputPacketBuffer[3] == 0x31)			// オンか?	
			button3->BackColor =Color:: Red;		// オンなら赤
		else
			button3->BackColor = Color::Green;		// オフなら緑

			 }

			 //
			 //		カメラデータをGet
			 //
private: System::Void button4_Click(System::Object^  sender, System::EventArgs^  e) {
			String^ temp_s;
			char* temp_c0;
			char temp_c1;
			char temp_c2;
			char temp_c3;

			read_ok = FALSE;

			temp_s = textBox2->Text;
//			MessageBox::Show(temp_s);
			if ( temp_s->Length != 2 )
			{
				MessageBox::Show("正しい値を入力してください。",
				"エラー",
				MessageBoxButtons::OK,
				MessageBoxIcon::Exclamation );
			}
			else
			{
//				marshal_context ^ context = gcnew marshal_context();
//				const char* str = context->marshal_as(temp_s);
//				delete context;
				temp_c0 = systemStringToChar(temp_s);

				temp_c1 = temp_c0[0];
				temp_c2 = temp_c0[1];
				temp_c3 = temp_c0[2];
				#ifdef _DEBUG
					System::Diagnostics::Debug::WriteLine("db1 temp_c1 =" + temp_c1);
					System::Diagnostics::Debug::WriteLine("db1 temp_c2 =" + temp_c2);
					System::Diagnostics::Debug::WriteLine("db1 temp_c3 =" + temp_c3);
				#endif
				if( !Uri::IsHexDigit( temp_c1 ) || !Uri::IsHexDigit( temp_c2 ))
				{
					MessageBox::Show("正しい値を入力してください。",
					"hexエラー",
					MessageBoxButtons::OK,
					MessageBoxIcon::Exclamation );
				}
				else
				{
					temp_c1 = toHex(temp_c0);
					#ifdef _DEBUG
						System::Diagnostics::Debug::WriteLine("temp_c1 = "+temp_c1.ToString());
					#endif

					OutputPacketBuffer[0] = 0;				// Report ID  
					OutputPacketBuffer[1] = 0x32;				// cam コマンド	   ic 0
					OutputPacketBuffer[2] = 0x31;				// cam getコマンド ic 1
					OutputPacketBuffer[3] = temp_c1;			// get address	   ic 2

		/* コマンド送信 */
					WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0);
		/* 状態送信要求 */
					ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0);
		/* 状態色変更 */
					if (InputPacketBuffer[1] == 0x32 && InputPacketBuffer[2] == 0x31 )
					{
						read_ok = TRUE;

						textBox3->Text = "get cam data add =";
						temp_c1 = InputPacketBuffer[3];
//						textBox3->Text += temp_c1.ToString("X");
						textBox3->Text += System::String::Format ("{0:X02}",temp_c1);
						textBox3->Text += ",  cam data =";
						temp_c1 = InputPacketBuffer[4];
				#ifdef _DEBUG
					System::Diagnostics::Debug::WriteLine("returnd temp_c1 = "+temp_c1.ToString());
				#endif
//						textBox3->Text += temp_c1.ToString("X");
						textBox3->Text += System::String::Format ("{0:X02}",temp_c1);
					}
					else
					{
						textBox3->Text = "not found data";
					}
				}
			}
		 }

		 //
		 //
		 //
private: int check_hex(char ch) {
			if('0' <= ch && ch <= '9') { return ch - '0'; }
			else if('a' <= ch && ch <= 'z') { return ch - 'a' + 10; }
			else if('A' <= ch && ch <= 'Z') { return ch - 'A' + 10; }
			else return -1;
		 }

private: char toHex(char* s) {
			int len = strlen(s);
			#ifdef _DEBUG
				System::Diagnostics::Debug::WriteLine("chr len ="+len.ToString());
			#endif
			int i = 0;
			int j = 0;
			unsigned char l = 0;
			while(len > 0) {
				i = check_hex(s[j]);
				#ifdef _DEBUG
					System::Diagnostics::Debug::WriteLine("hex comp ="+i.ToString());
				#endif
				if ( i < 0 )
				{
					#ifdef _DEBUG
						System::Diagnostics::Debug::WriteLine("hex sub error");
					#endif
				}
				j++;
				l = l * 16 + i;
				len--;
			}
			return l;
		 }

private: char* systemStringToChar(System::String^ systemStr)
	{
		using namespace System;
		using namespace System::Runtime::InteropServices;

		// 文字コードは、環境に合わせる(普通はUTF-8)
//		int len = Syetem::text::Encoding::getEncoding("UTF-8")->GetbyteCount(systemStr);
		int len = systemStr->Length;
		if( len > 0 ){
			char* rtnSts = new char[len+1];
			memset(rtnSts, 0x00, sizeof(char)*len+1);
			const char* buf = static_cast((Marshal::StringToHGlobalAnsi(systemStr)).ToPointer());
			// 取得した文字列をコピー
			strncpy_s(rtnSts, len+1, buf, _TRUNCATE);
			// メモリ開放
			Marshal::FreeHGlobal(IntPtr((void*)buf));
			return rtnSts;
		}
		return NULL;
	}

		 //
		 //
		 //
private: System::Void textBox2_TextChanged(System::Object^  sender, System::EventArgs^  e) {
		 }

		 //
		 //		cam data out
		 //
private: System::Void button5_Click(System::Object^  sender, System::EventArgs^  e) {
			String^ temp_s;
			char* temp_c0;
			char temp_c1;
			char temp_c2;
			char temp_c3;

			if (!read_ok)
			{
				MessageBox::Show("先に読み込みをして下さい。",
				"エラー",
				MessageBoxButtons::OK,
				MessageBoxIcon::Exclamation );
				return;
			}

			temp_s = textBox2->Text;
//			MessageBox::Show(temp_s);
			if ( temp_s->Length != 2 )
			{
				MessageBox::Show("正しい値を入力してください。",
				"エラー",
				MessageBoxButtons::OK,
				MessageBoxIcon::Exclamation );
			}
			else
			{
				temp_c0 = systemStringToChar(temp_s);

				temp_c1 = temp_c0[0];
				temp_c2 = temp_c0[1];
				temp_c3 = temp_c0[2];
				#ifdef _DEBUG
					System::Diagnostics::Debug::WriteLine("db1 temp_c1 =" + temp_c1);
					System::Diagnostics::Debug::WriteLine("db1 temp_c2 =" + temp_c2);
					System::Diagnostics::Debug::WriteLine("db1 temp_c3 =" + temp_c3);
				#endif
				if( !Uri::IsHexDigit( temp_c1 ) || !Uri::IsHexDigit( temp_c2 ))
				{
					MessageBox::Show("正しい値を入力してください。",
					"hexエラー",
					MessageBoxButtons::OK,
					MessageBoxIcon::Exclamation );
				}
				else
				{
					temp_c1 = toHex(temp_c0);
					#ifdef _DEBUG
						System::Diagnostics::Debug::WriteLine("temp_c1 = "+temp_c1.ToString());
					#endif

					OutputPacketBuffer[0] = 0;		// Report ID  
					OutputPacketBuffer[1] = 0x33;		// cam コマンド		ic 0
					OutputPacketBuffer[2] = 0x31;		// cam getコマンド	ic 1
					OutputPacketBuffer[3] = temp_c1;	// write address	ic 2

					temp_s = textBox4->Text;
//					MessageBox::Show(temp_s);
					if ( temp_s->Length != 2 )
					{
						MessageBox::Show("正しい値を入力してください。",
						"エラー",
						MessageBoxButtons::OK,
						MessageBoxIcon::Exclamation );
					}
					else
					{
						temp_c0 = systemStringToChar(temp_s);

						temp_c1 = temp_c0[0];
						temp_c2 = temp_c0[1];
						temp_c3 = temp_c0[2];
						#ifdef _DEBUG
							System::Diagnostics::Debug::WriteLine("db1 temp_c1 =" + temp_c1);
							System::Diagnostics::Debug::WriteLine("db1 temp_c2 =" + temp_c2);
							System::Diagnostics::Debug::WriteLine("db1 temp_c3 =" + temp_c3);
						#endif
						if( !Uri::IsHexDigit( temp_c1 ) || !Uri::IsHexDigit( temp_c2 ))
						{
							MessageBox::Show("正しい値を入力してください。",
							"hexエラー",
							MessageBoxButtons::OK,
							MessageBoxIcon::Exclamation );
						}
						else
						{
							temp_c1 = toHex(temp_c0);
							#ifdef _DEBUG
								System::Diagnostics::Debug::WriteLine("temp_c1 = "+temp_c1.ToString());
							#endif

							OutputPacketBuffer[4] = temp_c1;		// write data	ic 3
							/* コマンド送信 */
							WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0);
							/* 状態送信要求 */
							ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0);
							/* 状態色変更 */
							if (InputPacketBuffer[1] != 0x33 || InputPacketBuffer[2] != 0x31 )
							{
								textBox5->Text = "return error data";
							}
							else
							{
								textBox5->Text = "write cam data add =";
								temp_c1 = InputPacketBuffer[3];
								textBox5->Text += System::String::Format ("{0:X02}",temp_c1);
								textBox5->Text += ",  cam data =";
								temp_c1 = InputPacketBuffer[4];
					#ifdef _DEBUG
						System::Diagnostics::Debug::WriteLine("returnd temp_c1 = "+temp_c1.ToString());
					#endif
								textBox5->Text += System::String::Format ("{0:X02}",temp_c1);
							}
						}	//hex
					}	// length
				}
			}

		 }

		 //
		 //			チェックボタン
		 //
private: System::Void button6_Click(System::Object^  sender, System::EventArgs^  e) {
			int i_temp;

			switch (comboBox1->SelectedIndex)
			{
				case 0:
					#ifdef _DEBUG
						System::Diagnostics::Debug::WriteLine("select 1");
					#endif
					OutputPacketBuffer[0] = 0;		// Report ID  
					OutputPacketBuffer[1] = 0x34;		// cam コマンド		ic 0
					OutputPacketBuffer[2] = 0x31;		// cam getコマンド	ic 1

					/* コマンド送信 */
					WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0);
					/* 状態送信要求 */
					ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0);
					/* 状態色変更 */
					if (InputPacketBuffer[1] == 0x34 && InputPacketBuffer[2] == 0x31 )
					{
						#ifdef _DEBUG
							System::Diagnostics::Debug::WriteLine("returnd");
						#endif
						i_temp = InputPacketBuffer[3] * 256 + InputPacketBuffer[4];
						textBox6->Text = "get cam data H count =";
//						textBox6->Text += System::String::Format ("{0:X02}",InputPacketBuffer[3]);
//						textBox6->Text += System::String::Format ("{0:X02}",InputPacketBuffer[4]);
						textBox6->Text += i_temp.ToString();
					}
					else
					{
						textBox6->Text = "not found data";
					}

					break;
				case 1:
					#ifdef _DEBUG
						System::Diagnostics::Debug::WriteLine("select 2");
					#endif
					break;
				default:
					#ifdef _DEBUG
						System::Diagnostics::Debug::WriteLine("not select");
					#endif
					break;
			}
		 }

		 //
		 //		画像取込
		 //
private: System::Void button7_Click(System::Object^  sender, System::EventArgs^  e) {
//			 button7->BackColor = Color::Green;		// オフなら緑
			 capture_cam();
//			 button7->ResetBackColor();
		 }

private: void capture_cam()	{

			 this->Cursor = System::Windows::Forms::Cursors::WaitCursor;

			OutputPacketBuffer[0] = 0;					// Report ID  
			OutputPacketBuffer[1] = 0x35;				// cam コマンド			ic 0
			OutputPacketBuffer[2] = 0x31;				// cam getコマンド		ic 1
			/* コマンド送信 */
			WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0);
			/* 状態送信要求 */
			ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0);
			/* 状態色変更 */
			if (InputPacketBuffer[1] == 0x35 && InputPacketBuffer[2] == 0x31)
			{
				#ifdef _DEBUG
					System::Diagnostics::Debug::WriteLine("returnd");
				#endif
			}
			else
			{
				button7->BackColor = Color::Red;		//
			}
			/* 状態送信要求 */
			ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0);
			if (InputPacketBuffer[1] == 0x35 && InputPacketBuffer[2] == 0x32)
			{
				#ifdef _DEBUG
					System::Diagnostics::Debug::WriteLine("returnd get pic");
				#endif
			}
			else
			{
				button7->BackColor = Color::Red;		//
			}

			this->Cursor = System::Windows::Forms::Cursors::Default;
		 
		 }

		 //
		 //
		 //
private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
 				
			 timer1->Enabled = FALSE;
			 
			 capture_cam();
			 capture_data();

			 timer1->Enabled = TRUE;
		 }

		 //
		 //		画像転送
		 //
private: System::Void button8_Click(System::Object^  sender, System::EventArgs^  e) {
			 capture_data();
		 }

private: void capture_data() {

			 int	ix_v;
			 int	ix_h;
			 int	ix_hp;			// 画面描画用
			 BOOL	First_flg;
			 int	ix_hex;
			 String^ temp_s;

			 int	sw1;
			unsigned char temp_R1;
			unsigned char temp_G1;
			unsigned char temp_B1;
			unsigned char temp_R2;
//			unsigned char temp_G2;
//			unsigned char temp_B2;
			 Color temp_col;
			 unsigned char col_fact;

			 this->Cursor = System::Windows::Forms::Cursors::WaitCursor;

			//
			//		QVGA 544 * 408
			//
			//ピクチャボックスと同じ大きさのBitmapを作成
			//PictureBoxと同じ大きさのBitmapクラスを作成する。
			if ( pictureBox1->Image == nullptr )
			{
				#ifdef _DEBUG
					System::Diagnostics::Debug::WriteLine("pictureBox1->Image is NULL");
				#endif
			}
			else
			{
				#ifdef _DEBUG
					System::Diagnostics::Debug::WriteLine("pictureBox1->Image is not NULL");
				#endif
			}
			Bitmap^ bmp = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height);
			pictureBox1->Image = bmp;
   
			//ピクチャボックスからGraphicsの作成
			Graphics^ g = Graphics::FromImage(pictureBox1->Image);
			//ピクチャボックスの背景色でクリアする。
			g->Clear(pictureBox1->BackColor);
			 
			System::IO::StreamWriter^ temp_file = gcnew System::IO::StreamWriter("Camdata_Hex_Test.txt");
			temp_file->Write("カメラからのデータ\r\n");
			#ifdef _DEBUG
				System::Diagnostics::Debug::WriteLine("write test");
			#endif
			col_fact = 8;
			First_flg = TRUE;

			 for ( ix_v = 0; ix_v < 360; ix_v++ )
			 {		// loop V
				temp_s = "";
				ix_hp = 0;
				 for ( ix_h = 0; ix_h < 16; ix_h++ )			// 480*2/58-->16+32  
				 {		//  loop H
					OutputPacketBuffer[0] = 0;					// Report ID  
					OutputPacketBuffer[1] = 0x35;				// cam コマンド			ic 0
					OutputPacketBuffer[2] = 0x33;				// cam getコマンド		ic 1
					if ( First_flg )
					{
						OutputPacketBuffer[3] = 0x00;			// cam getコマンド		ic 2
						First_flg = FALSE;
					}
					else OutputPacketBuffer[3] = 0x01;			// cam getコマンド		ic 2
					/* コマンド送信 */
					WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0);
					/* 状態送信要求 */
					ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0);
					/* 状態色変更 */
					if (InputPacketBuffer[1] == 0x35 && InputPacketBuffer[2] == 0x33)
					{
//						#ifdef _DEBUG
//							System::Diagnostics::Debug::WriteLine("returnd get");
//						#endif
						sw1 = 0;
						for ( ix_hex = 4; ix_hex < 62; ix_hex++ )		//  58+4
						{	//	loop buf
							temp_s += System::String::Format ("{0:X02}",InputPacketBuffer[ix_hex]);

							sw1++;
//							#ifdef _DEBUG
//								System::Diagnostics::Debug::WriteLine("sw1 ="+sw1);
//							#endif
							if ( sw1 == 1 )
							{
								temp_R2 = InputPacketBuffer[ix_hex] / 16;
								temp_R1 = InputPacketBuffer[ix_hex] - ( temp_R2 * 16 );
								//  カラーの設定のみ
//					#ifdef _DEBUG
//						System::Diagnostics::Debug::WriteLine("temp_R1 ="+temp_R1+"  temp_G1 ="+temp_G1);
//					#endif
							}
							else if ( sw1 == 2 )
							{
								temp_G1 = InputPacketBuffer[ix_hex] / 16;
								temp_B1 = InputPacketBuffer[ix_hex] - ( temp_G1 * 16 );
//								temp_G1 = temp_G1 * 8 + temp_G2;
//						#ifdef _DEBUG
//							System::Diagnostics::Debug::WriteLine("temp_B1 ="+temp_B1+"  temp_R2 ="+temp_R2);
//						#endif
								//  カラーの設定 描画
								temp_col = Color::FromArgb( 255, temp_R1*col_fact, temp_G1*col_fact, temp_B1*col_fact );
								bmp->SetPixel( ix_hp, ix_v, temp_col );
								ix_hp++;
								sw1 = 0;
							}
							else
							{
								sw1 = 0;
//								temp_G2 = InputPacketBuffer[ix_hex] / 16;
//								temp_B2 = InputPacketBuffer[ix_hex] - ( temp_G2 * 16 );
//						#ifdef _DEBUG
//							System::Diagnostics::Debug::WriteLine("temp_G2 ="+temp_G2+"  temp_B2 ="+temp_B2);
//						#endif
								//  カラーの設定 描画
//								temp_col = Color::FromArgb( 255, temp_R2*16, temp_G2*16, temp_B2*16 );
//								bmp->SetPixel( ix_hp, ix_v, temp_col );
//								ix_hp++;
							}

						}	//  loop buf
//						temp_s += "\r\n";
//						temp_file->Write(temp_s);
//						temp_s = "";
					}
//					#ifdef _DEBUG
//						System::Diagnostics::Debug::WriteLine("cam data get");
//					#endif
				 }	//  loop H

				OutputPacketBuffer[0] = 0;					// Report ID  
				OutputPacketBuffer[1] = 0x35;				// cam コマンド			ic 0
				OutputPacketBuffer[2] = 0x33;				// cam getコマンド		ic 1
				OutputPacketBuffer[3] = 0x02;				// cam getコマンド		ic 2
				/* コマンド送信 */
				WriteFile(WriteHandle, &OutputPacketBuffer, 65, &BytesWritten, 0);
				/* 状態送信要求 */
				ReadFile(ReadHandle, &InputPacketBuffer, 65, &BytesRead, 0);
				/* 状態色変更 */
				if (InputPacketBuffer[1] == 0x35 && InputPacketBuffer[2] == 0x33)
				{
//					#ifdef _DEBUG
//						System::Diagnostics::Debug::WriteLine("returnd get2");
//					#endif
					sw1 = 0;
					for ( ix_hex = 4; ix_hex < 36; ix_hex++ )		//  32+4
					{		//  loop buf
						temp_s += System::String::Format ("{0:X02}",InputPacketBuffer[ix_hex]);

						sw1++;
//						#ifdef _DEBUG
//							System::Diagnostics::Debug::WriteLine("sw1 ="+sw1);
//						#endif
						if ( sw1 == 1 )
						{
							temp_R2 = InputPacketBuffer[ix_hex] / 16;
							temp_R1 = InputPacketBuffer[ix_hex] - ( temp_R2 * 16 );
							//  カラーの設定のみ
//					#ifdef _DEBUG
//						System::Diagnostics::Debug::WriteLine("temp_R1 ="+temp_R1+"  temp_G1 ="+temp_G1);
//					#endif
						}
						else if ( sw1 == 2 )
						{
							temp_G1 = InputPacketBuffer[ix_hex] / 16;
							temp_B1 = InputPacketBuffer[ix_hex] - ( temp_G1 * 16 );
//							temp_G1 = temp_G1 * 8 + temp_G2;
//					#ifdef _DEBUG
//						System::Diagnostics::Debug::WriteLine("temp_B1 ="+temp_B1+"  temp_R2 ="+temp_R2);
//					#endif
							//  カラーの設定 描画
							temp_col = Color::FromArgb( 255, temp_R1*col_fact, temp_G1*col_fact, temp_B1*col_fact );
							bmp->SetPixel( ix_hp, ix_v, temp_col );
							ix_hp++;
							sw1 = 0;
						}
						else
						{
							sw1 = 0;
//							temp_G2 = InputPacketBuffer[ix_hex] / 16;
//							temp_B2 = InputPacketBuffer[ix_hex] - ( temp_G2 * 16 );
//						#ifdef _DEBUG
//							System::Diagnostics::Debug::WriteLine("temp_G2 ="+temp_G2+"  temp_B2 ="+temp_B2);
//						#endif
							//  カラーの設定 描画
//							temp_col = Color::FromArgb( 255, temp_R2*16, temp_G2*16, temp_B2*16 );
//							bmp->SetPixel( ix_hp, ix_v, temp_col );
//							ix_hp++;
						}

					}		// loop buf
//					temp_s += "\r\n";
//					temp_file->Write(temp_s);
//					temp_s = "";
				}	
				temp_s += "\r\n";
				temp_file->Write(temp_s );
				temp_s = "";
			 }		// loop V

			temp_file->Close();

			textBox7->Text = "";
			for ( ix_hex = 0; ix_hex < 30; ix_hex++ )
			{
				textBox7->Text += System::String::Format ("{0:X02}",InputPacketBuffer[ix_hex]);
			}

			#ifdef _DEBUG
				System::Diagnostics::Debug::WriteLine("picture write test");
			#endif

			this->Cursor = System::Windows::Forms::Cursors::Default;

		 }


private: System::Void pictureBox1_Click(System::Object^  sender, System::EventArgs^  e) {
		 }


private: System::Void pictureBox1_Paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) {
			#ifdef _DEBUG
				System::Diagnostics::Debug::WriteLine("paint picture");
			#endif
//			e->Graphics->DrawLine( System::Drawing::Pens::Red, 0, 0,
//				pictureBox1->Right - pictureBox1->Left, pictureBox1->Bottom - pictureBox1->Top );
		 }

		 //
		 //		連続取込
		 //
private: System::Void button9_Click(System::Object^  sender, System::EventArgs^  e) {

			 if ( timer_get )
			 {
				 timer_get = FALSE;
				 button9->ResetBackColor();
				timer1->Enabled = FALSE;
			 }
			 else
			 {
				timer_get = TRUE;
				button9->BackColor = Color::Green;		// オフなら緑

				timer1->Interval = 1000;
				timer1->Enabled = TRUE;
			 }

		 }
};
}


HOME