※拡張子を変更してください。(〜.txt ⇒ 〜.c) /***************************************************** * File_Name:main.c for PIC 12F683 * 16ビットΔΣADC(MCP3425)を使った電圧計 * 表示 AQM1602Y_LNW_FBW(バックライト付き、黒地白文字) * ADC,LCDともにI2Cインターフェースで接続 * HI-TECH Cを使用 MPLAB IDE v8.84 ******************************************************/ #include /***** コンフィギュレーションの設定 ********/ __CONFIG(FOSC_INTOSCIO // INTOSCIO oscillator I/O function & WDTE_OFF // Watchdog Timer disabled & PWRTE_ON // Power-up Timer enabled & BOREN_ON // Brown Out enabled & MCLRE_ON // MCLR GP3pin function is reset & CP_OFF // Program memory code protection is disabled & IESO_OFF // Internal External Switchover mode is disabled & FCMEN_OFF ); // Fail-Safe Clock Monitor is disabled #define _XTAL_FREQ 1000000 // クロック周波数設定 #define SCL GP4 #define SDA GP5 #define TRISSDA TRISIO5 /** I2C関数 **/ void I2CStart(void); void I2CStop(void); unsigned char I2COut(unsigned char data); unsigned char I2CRcv(unsigned char Ack); /** lcd 関数 **/ void lcd_data(unsigned char data); void lcd_cmd(unsigned char cmd); void lcd_init(void); void lcd_str(const unsigned char* ptr); void lcd_clear(void); /** 関数 **/ void Adc_cfg(unsigned char data); // MCP3425動作設定 void GetDataI2C(unsigned char *Buffer, unsigned char Cnt); void ltostring(char digit, unsigned long data, char *buffer); void Hantei(void); void Display(void); void Disp_Over(void); /** 遅延関数 **/ void delay_5us(unsigned int time); void delay_5ms(unsigned int time); void delay_100ms(unsigned int time); /* グローバル変数 */ unsigned char Result[3]; // ADCより受信値 unsigned char Gain, hozon; // Gainの値と保存用 unsigned char i,j; // 回数カウント unsigned long Value; // 計測電圧値 /* 表示用データ */ const unsigned char Index1[] = "Max 2.04V Range "; const unsigned char Index2[] = "Max 250mV Range "; const unsigned char Msg1[] = "Volt= mV"; unsigned char Msg2[] = "+xx.xxx"; const unsigned char Title[]= { "Digital_V_meter " " AD_Conv MCP3425" }; /******** メイン関数 ************/ void main(void) { OSCCON = 0x40; // Set to 1MHz TRISIO = 0x00; // 全ポート出力設定(初期値) ANSEL = 0x00; // 全ポートデジタル設定 CMCON0 = 0x07; // コンパレータオフ OPTION_REG = 0x80; // pull_up disable // nGPPU = 1; プルアップ無効 GPIO = 0x38; // GP3,4,5 default High lcd_init(); // 液晶表示器の初期化 Value = 0; Gain = 1; // ADCの増幅率:1倍 hozon = 0; // 最初は異なる値に /************ LCD初期表示 **********/ j=0; lcd_cmd(0x80); // 1行目左端 for(i=0; i<16; i++) { // 左から1文字ずつ lcd_data(Title[j]); // タイトルを表示 delay_5ms(10); j++; } lcd_cmd(0xC0); // 2行目左端 for(i=0; i<16; i++) { lcd_data(Title[j]); delay_5ms(10); j++; } delay_100ms(10); lcd_clear(); /** メイン・ループ **/ while(1){ if(Gain == 1){ Adc_cfg(0x88); // ADC設定 単動作 16ビット Gain=1 }else{ Adc_cfg(0x8B); // ADC設定 〃 Gain=8 } delay_100ms(2); // 動作設定後の待機時間 GetDataI2C(Result, 2);// データ取得 Hantei(); } // End_while } // End_main /*** 測定値を換算し判定 ***/ void Hantei(void){ /* 測定値を数値に変換 */ if((Result[0] & 0x80) == 0){ // 正の値の場合 Value = (long)Result[0] * 256 + Result[1]; Msg2[0] = '+'; }else{ // 負の値の場合 Result[0] = ~Result[0]; // 0,1反転 Result[1] = ~Result[1]; // 0,1反転 Value = (long)Result[0] * 256 + Result[1] + 1; Msg2[0] = '-'; } /* 電圧の測定値への変換と表示 */ if(Gain == 1){ // ゲイン1倍の場合 (2V Range) Value = (Value*20480)/32768; // xxxx.xmVに変換 if(Value < 2400){ // 値が小さいか? Gain = 8; // 250mV Rangeへ }else if(Value > 20470){ // フルスケールオーバーか? Disp_Over(); // Range_Over表示 }else{ // (0.24〜2.04v) 正常範囲の場合 ltostring(5, Value, Msg2+1); // 文字に変換 Msg2[6] = Msg2[5]; // 小数部右移動 Msg2[5] = '.'; // 小数点追加 1234.5 Display(); } }else{ // ゲイン8倍の場合 (250mV Range) Value = (25600*Value)/32768; // xxx.xxmVに変換 if(Value > 25000){ // 250mVオーバーか? Disp_Over(); delay_100ms(5); Gain = 1; // 2V Rangeへ }else{ // ( 〜250mv)正常範囲の場合 ltostring(5, Value, Msg2+1);// 文字に変換 Msg2[6] = Msg2[5]; // 小数部右移動 Msg2[5] = Msg2[4]; // 123.45 Msg2[4] = '.'; // 小数点追加 Display(); } } } /** 表 示 **/ void Display(void){ lcd_cmd(0x80); // 1行目指定 if(hozon != Gain){ // Range 変更なら lcd_cmd(0x84); lcd_str(" "); lcd_cmd(0xC0); // 2行目先頭指定 lcd_str(Msg1); // 固定メッセージ表示 hozon = Gain; // 毎回表示するとチラチラするので } // Range変更時のみ再表示する if(Gain == 1){ // レンジチェック lcd_str(Index1); // 2V Range }else{ lcd_str(Index2); // 250mV Range } lcd_cmd(0xC6); // 数値位置へ移動 lcd_str(Msg2); // 測定値部更新 } /* Over表示 */ void Disp_Over(void){ lcd_cmd(0x80); lcd_str("** OVER-RANGE **"); } /*** ADCデータ取得 ***/ void GetDataI2C(unsigned char *Buffer, unsigned char Cnt){ unsigned char i; I2CStart(); // スタート出力 I2COut(0xD1); // アドレス送信 Readモード for(i=0; i0; i--) { // 変換は下位から上位へ buffer--; // ポインター1 *buffer = (data % 10) + '0'; // ASCIIへ data = data / 10; // 次の桁へ } } /*** ADCコンフィギュレーション設定 ***/ void Adc_cfg(unsigned char data){ I2CStart(); I2COut(0xD0); // アドレス送信 I2COut(data); // コマンドデータ送信 I2CStop(); // ストップ出力 } /*** スタート ***/ void I2CStart(void){ /* SCL,SDAは常時Highとする */ SDA = 0; // 先にSDA Low TRISSDA = 0; // SDA出力 } /*** ストップ ***/ void I2CStop(void){ SCL = 0; // SCL Low delay_5us(1); SDA = 0; // SDA Low TRISSDA = 0; // 出力モードに戻す SDA =Low SCL = 1; // 先にSCLをHigh delay_5us(1); SDA = 1; // 後からSDAをHigh delay_5us(10); // 間隔用遅延 } /*** 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; // ビット出力 else SDA = 0; // SDA Low BitPos = BitPos >> 1; // ビット位置移動 SCL = 1; // SCL Highに戻す } /* Ack チェック */ SCL = 0; // クロック1Low TRISSDA = 1; // 入力モードにしてACK入力 delay_5us(1); SCL = 1; // クロックHighに戻す delay_5us(1); ACK = SDA; // ACKチェック return(ACK); // ACKを戻り値とする } /*** I2Cで1バイト入力 ***/ unsigned char I2CRcv(unsigned char Ack){ int i; unsigned char BitPos, data; data = 0; BitPos =0x80; // ビット位置リセット for(i=0; i<8; i++){ // 8ビット繰り返し SCL = 0; // SCL Low TRISSDA = 1; // 入力モード delay_5us(1); // 幅確保 SCL = 1; // SCL High if(SDA) // ビット入力 data |= BitPos; BitPos = BitPos >> 1; // ビットシフト } /* ACK/NAK出力 */ SCL = 0; // SCL Low SDA = Ack; // ACK ot NAK 出力 TRISSDA = 0; // SDA出力モード delay_5us(1); // パルス幅確保 SCL = 1; // SCL High return(data); // 受信データを戻す } /*** 液晶へ1文字表示 ***/ void lcd_data(unsigned char data){ I2CStart(); // スタート I2COut(0x7C); // アドレス I2COut(0x40); // 表示データ指定 I2COut(data); // 表示データ出力 I2CStop(); // ストップ delay_5us(6); // 遅延 } /*** 液晶へ1コマンド出力 ***/ void lcd_cmd(unsigned char cmd){ I2CStart(); // スタート I2COut(0x7C); // アドレス I2COut(0x00); // コマンド指定 I2COut(cmd); // コマンド出力 I2CStop(); // ストップ /* ClearかHomeか */ if((cmd == 0x01)||(cmd == 0x02)) delay_5ms(1); // 5msec待ち else delay_5us(6); // 30μsec待ち } /*** LCD 初期化 ***/ void lcd_init(void){ delay_100ms(1); lcd_cmd(0x38); // 8bit 2line Normal mode delay_5us(6); lcd_cmd(0x39); // 8bit 2line Extend mode delay_5us(6); lcd_cmd(0x14); // OSC 183Hz BIAS 1/5 delay_5us(6); /** コントラスト設定 **/ lcd_cmd(0x75); // Contrast set delay_5us(6); lcd_cmd(0x56); // Power/ICON/Contrast control delay_5us(6); lcd_cmd(0x6C); // Follwer for 3.3V delay_100ms(2); lcd_cmd(0x38); // 標準コマンド指定=0x38 delay_5us(6); lcd_cmd(0x01); // Clear Display( =0x01) delay_5us(6); lcd_cmd(0x0C); // Display On/Off Control( =0x0C) delay_5us(6); lcd_cmd(0x06); // EntryModeSet:カーソルは右へ=0x06(通常) delay_5ms(1); } /*** 全消去 ***/ void lcd_clear(void) { lcd_cmd(0x01); // 画面クリア } /*** 文字列表示 ***/ void lcd_str(const unsigned char* ptr) { while(*ptr != 0) //文字取り出し lcd_data(*ptr++); //文字表示 } /*** 5us単位タイマ ***/ void delay_5us(unsigned int time){ while(time){ __delay_us(1); // 5usec time--; // 5usec x time } } /*** 5ms単位タイマ ***/ void delay_5ms(unsigned int time){ while(time){ __delay_ms(5); // 5msec time--; // 5msec x time } } /*** 100ms単位タイマ ***/ void delay_100ms(unsigned int time){ while(time){ __delay_ms(100);// 100msec time--; // 100msec x time } }