I2Cデバイス アドレスをスキャンする (PIC 12F1822)

戻る一つ前のメニューに戻る

I2Cバスに接続された全てのデバイスのアドレス一覧を、液晶表示とシリアル出力するユニットの製作。

目次

主な機能

  • 動作電圧 3.3V, 5.0V
  • LCD表示(スキャン中表示、結果表示)
  • シリアル接続(RS232C接続)によるPCへのデータ転送
  • トリガボタンまたは端末からのリターンキー入力により再スキャン

回路図・部品表

i2c-scanner-circuit.png

BSch3V用回路図ファイルをダウンロードする

名称 型番・仕様 個数・価格
PICマイコン 12F1822 1個(145円)
I2C EEPROM 24LC64 1個(80円)
I2C液晶 Strawberry Linux SB1602B 1個(700円)
炭素皮膜抵抗 10kΩ 1個(5円)
炭素皮膜抵抗 1kΩ 1個(5円)
タクトスイッチ 1個(35円)

I2C EEPROMはアドレス検索対象とするためのダミーのスレーブデバイス。

完成写真およびシリアル出力例

i2c-scanner-board.jpg


I2C addr scan
 --  --  --  --  --  --  --  --  08  09  0A  0B  0C  0D  0E  0F
 10  11  12  13  14  15  16  17  18  19  1A  1B  1C  1D  1E  1F
 20  21  22  23  24  25  26  27  28  29  2A  2B  2C  2D  2E  2F
 30  31  32  33  34  35  36  37  38  39  3A  3B  3C  3D [3E] 3F
 40  41  42  43  44  45  46  47  48  49  4A  4B  4C  4D  4E  4F
 50 [51] 52  53  54  55  56  57  58  59  5A  5B  5C  5D  5E  5F
 60  61  62  63  64  65  66  67  68  69  6A  6B  6C  6D  6E  6F
 70  71  72  73  74  75  76  77  --  --  --  --  --  --  --  --
 --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
 --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
 --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
 --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
 --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
 --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
 --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
 --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
found:3E, 51,

ソースコード

XC8 C言語ソースコード、ビルド済みHEXファイル、回路図のダウンロード
動作確認済み開発環境
  • Microchip MPLAB X IDE ver 1.30
  • Microchip MPLAB XC8 ver 1.01
メイン関数部分の抜粋

※ライブラリ(i2c-lib, serial-lib)はSubversionブラウザにのみ掲載。

Thermometer-main.c
#include <stdio.h>
#include <stdlib.h>
 
#include <xc.h>
#include "i2c-lib.h"
#include "serial-lib.h"
 
/* PIC Configuration 1 */
__CONFIG(FOSC_INTOSC &	// INTOSC oscillator: I/O function on CLKIN pin
		WDTE_OFF &		// WDT(Watchdog Timer) disabled
		PWRTE_ON &		// PWRT(Power-up Timer) disabled
		MCLRE_OFF &		// MCLR pin function is digital input
		CP_OFF &		// Program memory code protection is disabled
		CPD_OFF &		// Data memory code protection is disabled
		BOREN_OFF &		// BOR(Brown-out Reset) disabled
		CLKOUTEN_OFF &	// CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
		IESO_OFF &		// Internal/External Switchover mode is disabled
		FCMEN_OFF);		// Fail-Safe Clock Monitor is disabled
 
/* PIC Configuration 2 */
__CONFIG(WRT_OFF &		// Flash Memory Self-Write Protection : OFF
		VCAPEN_OFF &	// VDDCORE pin functionality is disabled
		PLLEN_OFF &		// 4x PLL disabled
		STVREN_ON &		// Stack Overflow or Underflow will not cause a Reset
		BORV_HI &		// Brown-out Reset Voltage Selection : High Voltage
		DEBUG_OFF &		// In-Circuit Debugger disabled, ICSPCLK and ICSPDAT are general purpose I/O pins
		LVP_OFF);		// Low-voltage programming : disable
 
 
#ifndef _XTAL_FREQ
	/* 例:4MHzの場合、4000000 をセットする */
	#define _XTAL_FREQ 4000000
#endif
 
// スキャンするI2Cアドレスの範囲
#define I2C_ADDR_FIRST	0b0000111	// 0~0b111はシステムで予約されている
#define I2C_ADDR_LAST	0b1111000	// 0b11110000以降はシステムで予約されている
 
/*
 * 
 */
/* printf関数の出力先のスタブ関数を定義する */
void putch(unsigned char ch){
	i2c_lcd_putch(ch);
//	rs232c_putch(ch);
	return;
}
 
int main(int argc, char** argv) {
	// 基本機能の設定
	OSCCON = 0b01101010;		// 内部オシレーター 4MHz
	TRISA = 0b00101111;			// IOポートRA0(AN0),RA1(SCL),RA2(SDA),RA5(RX)を入力モード(RA3は入力専用)、RA4(TX)を出力モード
	APFCONbits.RXDTSEL = 1;		// シリアルポート RXをRA5ピンに割付
	APFCONbits.TXCKSEL = 1;		// シリアルポート TXをRA4ピンに割付
	ANSELA = 0b00000001;		// A/D変換をAN0を有効、AN1,AN2,AN4を無効
	PORTA = 0;
	INTCONbits.PEIE = 1;		// 割り込み機能をON (RX受信割り込みを使う場合)
	INTCONbits.GIE = 1;			// 割り込み機能をON (RX受信割り込みを使う場合)
 
	i2c_enable();
	OPTION_REGbits.nWPUEN = 0;	// I2C プルアップ抵抗 有効
	WPUA = 0b00000110;			// pull-up (RA1=SCL, RA2=SDA pull-up enable)
 
	ADCON0 = 0;					// AN0選択, A/D機能停止
	ADCON1 = 0b10010000;		// 変換結果右詰, クロックFOSC/4, 比較対象VDD
 
	// 0.5秒待つ
	__delay_ms(500);
 
	rs232c_init(9600);
 
	while(1)
	{
		int i,j;
		char temp_str[6];	// 表示用に数値をフォーマットするために利用
		unsigned int found_addr[10];	// 見つかったi2cアドレス
		for(j=0; j<10; j++) found_addr[j] = 0;
		int found_addr_count = 0;		// 見つかったアドレスの個数
 
		i2c_lcd_init();
		i2c_lcd_puts("I2C addr scan");
		rs232c_puts("\r\nI2C addr scan\r\n");
 
		for(i=0; i<=0xff; i+=0x10)
		{
 
			for(j=0; j<=0xf; j++)
			{
				unsigned int i2c_addr = i+j;
				i2c_lcd_set_cursor_pos(0x40);		// 2行目の1文字目に移動
				printf("scan %02X-%02X", i, i+0xf);
				// システムで予約された範囲のアドレスはスキャンしない
				if(i2c_addr <= I2C_ADDR_FIRST || i2c_addr >= I2C_ADDR_LAST)
				{
					rs232c_puts(" -- ");
				}
				else
				{
					i2c_start();
					i2c_send_byte(i2c_addr<<1);	// アドレスを1ビット左にシフトし、末尾にR/Wビット(Write=0)を付与
					if(SSP1CON2bits.ACKSTAT){
						// ACKが検出されなかった場合
						sprintf(temp_str, " %02X ", i2c_addr);
						rs232c_puts(temp_str);
					}
					else{
						// ACKが検出されなかった場合
						sprintf(temp_str, "[%02X]", i2c_addr);
						rs232c_puts(temp_str);
						found_addr[found_addr_count++] = i2c_addr;
					}
					i2c_stop();
 
					// I2Cバスを切・入して通信途中で放置した動作を一旦リセットする
					i2c_disable();
					__delay_ms(20);
					i2c_enable();
				}
			}
			rs232c_puts("\r\n");
		}
 
		// 最終行に、見つかったI2Cアドレス一覧を表示
		i2c_lcd_set_cursor_pos(0x40);		// 2行目の1文字目に移動
		for(j=0;j<16;j++) i2c_lcd_putch(' ');	// 2行目クリア
		i2c_lcd_set_cursor_pos(0x40);		// 2行目の1文字目に移動
		rs232c_puts("found:");
		for(j=0; j<found_addr_count; j++)
		{
			printf("%02X,", found_addr[j]);	// 見つかったアドレスをLCDに表示
			sprintf(temp_str, "%02X, ", found_addr[j]);
			rs232c_puts(temp_str);
		}
		rs232c_puts("\r\n");
 
		// RS232C入力またはRA3ボタンが押されるまで待つ
		while(1)
		{
			// 0.5秒待つ
			__delay_ms(500);
 
			// RS232Cで改行を伴う文字列入力を検知した場合
			if(flag_rs232c_received == 1)
			{
				rs232c_buffer[0] = (char)0;
				flag_rs232c_received = 0;
				break;
			}
 
			// RA3ボタンが押された場合
			if(!PORTAbits.RA3)
			{
				break;
			}
		}
	}
 
	return (EXIT_SUCCESS);
 
}

関連記事

 

戻る一つ前のメニューに戻る