#analog
#norelated
#contents
* A/D変換サンプル [#a65c1d55]

A/D変換機能を使って、アナログな電圧を数値化する。~
今回はこれとフォトトランジスタを使って、照度計を作ってみよう。~

** 回路図 [#rac11946]

#ref(ADConvTest_old.png,left,nowrap,A/D変換サンプル)

LCDの回路に、フォトトランジスタ(NJL7502L)と、レンジ切り替え用の抵抗を4種類追加。~
データシートによれば、光が当たることにより流れる電流は、0.3μA〜10mA。~
てことは、オームの法則でこんな感じ?~

 最小レンジ:E=0.0000003(0.3μ)A*100000(100k)Ω=0.03V
 最大レンジ:E=0.01(10m)A*100Ω=1V

A/D変換の精度は10bit(1024段階)なので、基準の5Vを1024で割って、最小0.005Vくらいか。~
最小レンジの方が微妙かと思ったけど、変化を捕まえられないことはないかね。~
まぁ、このあたりだと、データシートでは10ルクスにも届かないような範囲なので、ロウソク未満、月明かりくらい……?

----

で、書いて試してみてから気づいたんだけどね?~
普段、AVRをいじってるのは夜の時間帯で、せいぜいが蛍光灯の明かりなわけですよ。~
昼間だったとしても、窓と反対側の壁際にいるので、下手したら蛍光灯より暗いわけですよ。~

で、蛍光灯の下で、100kΩの抵抗をつけて、最小レンジで計ってみても、最大値はぎりぎり5V*(1000/1024)いくかどうかってとこで、あとちょっとなんだけど、オーバーフローするところまでいかないのね。~
安い懐中電灯を買ってきて、直接当ててみても、同じくらいだった。~

てことは、流れてる電流は、I=(5V*1000/1024)/100000(100k)Ω=0.000049(49μ)Aなんで、これをルクスに換算すると、100〜200ルクス。~
レンジ切り替えをする意味がないようです。~
というわけで、今回は、100kΩの抵抗のみでいきます。~
1MΩの抵抗とかがあれば、100kΩと切り替えて使えるかもね。~

#ref(ADConvTest.png,left,nowrap,A/D変換サンプル)

LCDの回路に、フォトトランジスタと、レンジ切り替え用の抵抗を4種類。~

** ソースコード [#m3e37833]

ソースは今回は、前にやったLCD表示も使うので、この辺はライブラリ(というか別ソース)にした。

-util.h

 #ifndef UTIL_H_
 #define UTIL_H_
 
 #include <util/delay.h>
 
 void delay_ms( uint16_t time );
 
 #endif /* UTIL_H_ */

-util.c

 #include "util.h"
 
 void delay_ms( uint16_t time )
 {
 	// 指定ms分ループ
 	while( time-- ){
 		_delay_ms( 1 );
 	}
 }

-lcdlib.h

 #ifndef LCDLIB_H_
 #define LCDLIB_H_
 
 #include <avr/io.h>
 
 #define LCD_PORT	PORTD	// LCD表示に使用する出力レジスタ
 #define LCD_PIN	PIND	// LCD表示に使用する入力レジスタ
 #define LCD_DDR	DDRD	// LCD表示に使用する方向レジスタ
 
 #define LCD_D4	(1<<0)	// D4ビット位置
 #define LCD_D5	(1<<1)	// D5ビット位置
 #define LCD_D6	(1<<2)	// D6ビット位置
 #define LCD_D7	(1<<3)	// D7ビット位置
 #define LCD_E	(1<<5)	// Eビット位置
 #define LCD_RW	(1<<6)	// R/Wビット位置
 #define LCD_RS	(1<<7)	// RSビット位置
 #define LCD_DATMASK	0x0F	// データビットマスク
 
 // RSモード列挙型定義
 typedef enum _tagRSMode{
 	RS_MODE_COMMAND,	// コマンドモード
 	RS_MODE_DATA,		// データモード
 } RSMode;
 
 void Lcd_init( void );
 void Lcd_setpos( int8_t x, int8_t y );
 void Lcd_setchar( char data );
 void Lcd_setstr( char *str );
 void Lcd_setcmd( uint8_t cmd );
 
 
 #endif /* LCDLIB_H_ */

-lcdlib.c

 #include "LcdLib.h"
 #include "util.h"
 
 void lcd_busywait( void )
 {
 	uint8_t	bf = LCD_D7;	// Busyフラグが立った状態の変数を初期化
 
 	// RSビットはクリアでコマンドモード
 	LCD_PORT &= ~( LCD_RS );
 
 	// ReadモードはRWビットを立てる
 	LCD_PORT |= ( LCD_RW );
 
 	// データビットを入力に設定
 	LCD_DDR	&= ~( LCD_DATMASK );
 
 	// Busyフラグが落ちるまでループ
 	while( bf ){
 		// イネーブルパルス出力(上位4bit)
 		LCD_PORT |= LCD_E;
 			// 高速駆動時はここでイネーブルパルス幅以上待つ必要があるはず
 		bf = LCD_PIN & ( 1 << LCD_D7 );	// Busyフラグの読み出し
 		LCD_PORT &= ~LCD_E;
 			// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要があるはず
 
 		// イネーブルパルス出力(下位4bit/4bitモードなので2回送る必要があるがここでは特にすることはない)
 		LCD_PORT |= LCD_E;
 			// 高速駆動時はここでイネーブルパルス幅以上待つ必要があるはず
 		LCD_PORT &= ~LCD_E;
 			// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要があるはず
 	}
 
 	// データビットを出力に戻す
 	LCD_DDR	|= ( LCD_DATMASK );
 }
 
 void lcd_setcmd4( RSMode mode, uint8_t data )
 {
 	uint8_t	tmpval = LCD_PORT;	// ポート状態を一旦変数に入れる
 
 	// 書き込むポートを一旦落とす
 	tmpval &= ~( LCD_RW | LCD_RS | LCD_DATMASK );
 
 	// RSビットコマンドモードであればクリアのまま
 	if( RS_MODE_DATA == mode ){
 		tmpval |= LCD_RS;	// RSビットはデータモードであれば立てる
 	}
 
 	// RWビットはクリアでWriteモードなのでそのまま
 
 	// データビットセット(下位4bitのみセットするのマスク)
 	tmpval |= ( LCD_DATMASK & data );
 
 	// ポートに書き込み
 	LCD_PORT = tmpval;
 
 	// イネーブルパルス出力
 	LCD_PORT |= LCD_E;
 		// 高速駆動時はここでイネーブルパルス幅以上待つ必要があるはず
 	LCD_PORT &= ~LCD_E;
 		// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要があるはず
 }
 
 void Lcd_setcmd( uint8_t cmd )
 {
 	// 上位4bit送信
 	lcd_setcmd4( RS_MODE_COMMAND, LCD_DATMASK & ( cmd >> 4 ));
 	// 下位4bit送信
 	lcd_setcmd4( RS_MODE_COMMAND, LCD_DATMASK & cmd );
 	// Busyチェック
 	lcd_busywait();
 }
 
 void Lcd_setchar( char data )
 {
 	// 上位4bit送信
 	lcd_setcmd4( RS_MODE_DATA, LCD_DATMASK & ( data >> 4 ));
 	// 下位4bit送信
 	lcd_setcmd4( RS_MODE_DATA, LCD_DATMASK & data );
 	// Busyチェック
 	lcd_busywait();
 }
 
 void Lcd_setstr( char *str )
 {
 	// 終了(NULL文字までループ)
 	while( *str ){
 		// 1文字ずつ設定
 		Lcd_setchar( *str );
 		str++;
 	}
 }
 
 void Lcd_init( void )
 {
 	// 最初は全てのポートを出力に設定
 	LCD_DDR	|= ( LCD_E | LCD_RW | LCD_RS | LCD_DATMASK );
 	// 信号もLowにしておく
 	LCD_PORT &= ~( LCD_E | LCD_RW | LCD_RS | LCD_DATMASK );
 
 	// 最初はBusyチェックが効かないので、時間待ちする
 	delay_ms( 15 );		// 15ms待ち
 	lcd_setcmd4( RS_MODE_COMMAND, 0x3 );	// 8bitモード設定
 	delay_ms( 5 );		// 4.1ms以上待ちなので、5ms待ち
 	lcd_setcmd4( RS_MODE_COMMAND, 0x3 );	// 8bitモード設定
 	delay_ms( 1 );		// 100μs以上待ちなので、とりあえず1ms待っておく
 	lcd_setcmd4( RS_MODE_COMMAND, 0x3 );	// 8bitモード設定
 	delay_ms( 1 );		// ファンクションセットは39μs以上待ちなので、とりあえず1ms待っておく
 
 	// 初期化シーケンスに書いてある通り、4bitの設定は4bitのみ渡せれば有効なので、1回のみ
 	lcd_setcmd4( RS_MODE_COMMAND, 0x2 );	// 4bitモード設定
 	delay_ms( 1 );		// ファンクションセットは39μs以上待ちなので、とりあえず1ms待っておく
 
 	// ここからは4bitモード動作なので、8bitの命令を4bitずつ2回に分けて送ってやる
 	lcd_setcmd4( RS_MODE_COMMAND, 0x2 );	// ファンクションセット、4bitモード
 	lcd_setcmd4( RS_MODE_COMMAND, 0x8 );	// 2Line表示、5*8ドットフォント
 	delay_ms( 1 );		// ファンクションセットは39μs以上待ちなので、とりあえず1ms待っておく
 	lcd_setcmd4( RS_MODE_COMMAND, 0x0 );	// Display ON/OFF設定
 	lcd_setcmd4( RS_MODE_COMMAND, 0xF );	// Display ON / Cursor ON / Blinking ON
 	delay_ms( 1 );		// Display ON/OFF設定は39μs以上待ちなので、とりあえず1ms待っておく
 	lcd_setcmd4( RS_MODE_COMMAND, 0x0 );	// Clear Displayコマンド
 	lcd_setcmd4( RS_MODE_COMMAND, 0x1 );	// スペースでDDRAMが埋められ、アドレスカウンタがDDRAMの00H(先頭)に移動
 	delay_ms( 2 );		// Clear Displayコマンドは1.53ms以上待ちなので、2ms待ち
 	lcd_setcmd4( RS_MODE_COMMAND, 0x0 );	// Entry Mode
 	lcd_setcmd4( RS_MODE_COMMAND, 0x6 );	// インクリメントモード / ディスプレイシフトなし
 	delay_ms( 1 );		// Entry Modeコマンドは39μs以上待ちなので、とりあえず1ms待っておく
 }
 
 void Lcd_setpos( int8_t x, int8_t y )
 {
 	int8_t val = 0x80;	// コマンドコード設定
 
 	if( x ) val |= 0x40;	// 行指定が0(1行目)じゃなかったら、2行目bitを立てる
 	val |= ( y & 0x0f );	// 列指定の4bitを設定する
 
 	// コマンド送信
 	Lcd_setcmd( val );
 }

*** 基本動作 [#af0c8e19]


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS