拡張子を変更してください。 .txt → .c Web-Pageに戻るには、<戻る←>ボタンで /*************************************************************** * LCD(1602A-I2C)表示の交流電圧計プログラム for 12F683 * HI-TECH Cを使用 * 1/50倍とノーマル(増幅も減衰もなし)と10倍増幅をSWで切り替え。 * PICのモード切り替えは、GP1とGP2の値により切り替える。 * A/Dコンバータの基準は、Vdd(3.3v)。シャントレギュレータで安定化。 * Volt1の数値合わせ(*520/810)は実測値によって調整。 * GP0:計測電圧(入力) GP1,GP2:レンジ切り替えスイッチ(01 or 10 or 11) * GP3:Free GP4:SDA GP5:SCL ****************************************************************/ #include #define _XTAL_FREQ 4000000 // クロック周波数設定 /***** コンフィギュレーションの設定 ********/ __CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & BOREN_ON & MCLRE_OFF & CP_OFF & IESO_OFF & FCMEN_OFF); #define SDA GP4 #define SCL GP5 #define TRISSDA TRISIO4 void I2CStart(void); void I2CStop(void); unsigned char I2COut(unsigned char data); void lcd_data(unsigned char data); void lcd_cmd(unsigned char cmd); void lcd_init(void); void lcd_str(char* ptr); void lcd_clear(void); void delay_10ms(unsigned int time); void itostring(char digit, unsigned int data, char *buffer); unsigned char Msg1[17] = "****V RANGE "; unsigned char Msg2[17] = "Volt = x,xxx mV"; unsigned char Kari[5]; unsigned char int_sw; void key(void); unsigned int keisoku(unsigned char port); void hyoji(); /******** メイン関数 ************/ void main(void) { unsigned int Volt1; // 計測電圧 unsigned char i; OSCCON = 0x60; // Set to 4MHz TRISIO = 0x07; // GP 基本出力設定(GP0,1,2は入力) ANSEL = 0x01; // 基本デジタル、GP0はアナログ(ADC)設定 CMCON0 = 0x07; // コンパレータオフ ADCON0 = 0b10000001; // ADコンバータ設定、基準は、Vdd(+3.3v) /* AD変換クロック設定 */ ADCS2=0; ADCS1=1; ADCS0=0; // Fosc/32 GP3 = 0; // 空きピン処理 /* 液晶表示器の初期化 */ lcd_init(); /**** メインループ *****/ while(1){ Volt1 = keisoku(0); // GP0の値 key(); if(int_sw == 3)Volt1 = Volt1 * 5; // 50Vレンジなら Volt1 = (long)Volt1 * 3300 / 1023; // 3.3v と比較 Volt1 = (long)Volt1 * 520 / 810; // 数値合わせ(ここで調整する) itostring(4, Volt1++, Kari); // 4桁の文字データ→Kari hyoji(); lcd_cmd(0x80); // 1行目の左端 lcd_str(Msg1); lcd_cmd(0xC0); // 2行目の左端 lcd_str(Msg2); delay_10ms(10); } // end_while } /* 基準電圧はシャントレギュレータによる3.3v 計測電圧は、GP0 で、0〜3.3v */ // 計測サブ 100回計測+10倍->合計->1/10 平均 四捨五入 unsigned int keisoku(unsigned char port){ unsigned long kei; unsigned int value; unsigned char i; port = port << 2; kei = 0; for(i = 0;i < 100;i++){ ADCON0 = 0b10000001 | port; delay_10ms(1); GO = 1; while(GO); // GO = GODONEビット 0になるまで待つ kei = kei + (ADRESH * 256 + ADRESL) * 10; // 10倍して加算 } value = (kei / 100 + 5) / 10 ; // 平均して四捨五入 return(value); } /*************************************** * int整数からASCII文字に変換 ****************************************/ void itostring(char digit, unsigned int data, char *buffer) { char i; buffer += digit; // 最後の数字位置 for(i=digit; i>0; i--) { // 変換は下位から上位へ buffer--; // ポインター1 *buffer = (data % 10) + '0'; // ASCIIへ data = data / 10; // 次の桁へ } } // キー入力 void key(void){ // GP1,2の状態を調べる int_sw = GPIO; // ポート全部をコピーして int_sw &= 0x06; // GP1,2のみをDATAとしてinput int_sw = int_sw>>1; // 数値にするためシフト // 値は、11(=3:信号なし)から00(=0:2ポートon)まで4種類 } /**************************************** * LCD表示用 GP1,2 の On/Off により表示を変更 *****************************************/ void hyoji(){ switch(int_sw){ case 1: // 2Vレンジ Msg1[0] = ' '; Msg1[1] = ' '; Msg1[2] = '2'; Msg1[3] = ' '; if(Kari[0] == '0'){ Msg2[8] = ' '; Msg2[9] = ' '; } else{ Msg2[8] = Kari[0]; Msg2[9] = ','; } Msg2[10] = Kari[1]; Msg2[11] = Kari[2]; Msg2[12] = Kari[3]; Msg2[14] = 'm'; Msg2[15] = 'V'; break; case 2: // 0.2Vレンジ Msg1[0] = '0'; Msg1[1] = '.'; Msg1[2] = '2'; Msg1[3] = ' '; if(Kari[0] == '0'){ Msg2[8] = ' '; if(Kari[1] == '0')Msg2[9] = ' '; }else{ Msg2[8] = Kari[0]; Msg2[9] = Kari[1]; Msg2[10] = Kari[2]; Msg2[11] = '.'; Msg2[12] = Kari[3]; } Msg2[14] = 'm'; Msg2[15] = 'V'; break; case 3: // 50Vレンジ Msg1[0] = ' '; Msg1[1] = '5'; Msg1[2] = '0'; Msg1[3] = ' '; if(Kari[0] == '0'){ Msg2[8] = ' '; } else { Msg2[8] = Kari[0]; } Msg2[9] = Kari[1]; Msg2[10] = '.'; Msg2[11] = Kari[2]; Msg2[12] = Kari[3]; Msg2[14] = ' '; Msg2[15] = 'V'; break; } } /***************************** * Start Condiotion *****************************/ void I2CStart(void) { /* SCL,SDAは常時Highとする */ SDA = 0; // 先に SDA=Low TRISSDA = 0; // SDA出力 } /***************************** * Stop Condition *****************************/ void I2CStop(void) { SCL = 0; // SCL Low SDA = 0; // SDA Low TRISSDA = 0; // 出力モードに戻す SCL = 1; // 先にSCLをHigh SDA = 1; // 後からSDAをHigh } /**************************** * I2Cで1バイト出力 ****************************/ unsigned char I2COut(unsigned char data) { int i; unsigned char BitPos, ACK; /* Data Out */ TRISSDA = 0; // SDA出力モード BitPos = 0x80; // ビット位置初期値 for(i=0; i<8; i++) // 8ビット繰り返し { SCL = 0; // SCL Low if((data & BitPos) != 0) // ビット出力 SDA = 1; // SDA High else SDA = 0; // SDA Low BitPos = BitPos >> 1; // ビット位置移動 SCL = 1; // SCL Highに戻す } /* Ack チェック */ SCL = 0; // クロック1Low TRISSDA = 1; // 入力モードにしてACK入力 ACK = SDA; // ACKチェック for delay ACK = SDA; // ACKチェック SCL = 1; // クロックHighに戻す return(ACK); // ACKを戻り値とする } /********************************* * 液晶へ1文字表示データ出力 *********************************/ void lcd_data(unsigned char data) { I2CStart(); // スタート I2COut(0x7C); // アドレス I2COut(0x40); // 表示データ指定 I2COut(data); // 表示データ出力 I2CStop(); // ストップ __delay_us(30); // 遅延 } /******************************* * 液晶へ1コマンド出力 *******************************/ void lcd_cmd(unsigned char cmd) { I2CStart(); // スタート I2COut(0x7C); // アドレス I2COut(0x00); // コマンド指定 I2COut(cmd); // コマンド出力 I2CStop(); // ストップ /* ClearかHomeか */ if((cmd == 0x01)||(cmd == 0x02)) __delay_ms(2); // 2msec待ち else __delay_us(30); // 30μsec待ち } /******************************* * 初期化関数 *******************************/ void lcd_init(void) { delay_10ms(10); lcd_cmd(0x38); // 8bit 2line Normal mode lcd_cmd(0x39); // 8bit 2line Extend mode lcd_cmd(0x14); // OSC 183Hz BIAS 1/5 lcd_cmd(0x7F); // Contrast set 3.3v 0111YYYY lcd_cmd(0x55); // power/contrast 010101XX // XXYYYY 0-63段階 Now(011111) lcd_cmd(0x6C); delay_10ms(20); lcd_cmd(0x38); // Set Normal mode lcd_cmd(0x01); // Clear Display lcd_cmd(0x0C); // Display On } /****************************** * 全消去関数 ******************************/ void lcd_clear(void) { lcd_cmd(0x01); // クリアコマンド出力 } /***************************** * 文字列表示関数 *****************************/ void lcd_str(char* ptr) { while(*ptr != 0) //文字取り出し lcd_data(*ptr++); //文字表示 } /****************************** * 10msec遅延関数 ******************************/ void delay_10ms(unsigned int time) { while(time){ __delay_ms(10); // 10msec time--; // 10msec x time } }