/********************************************************** * PIC18F14K50 * * HX711_TEST:ロードセル用24bitADモジュールを試す。XC8版 * 参考サイト:O-Familyさん * * ロードセル:SC616C-500g(シングルポイント・ビーム型) *       定格荷重= 500g *       定格出力= 0.7mV/V±0.15mV/V * * 内蔵発振器:16MHz使用 * Tcy= 1/(16M/4)= 250nS * * * 初期作成日:2019/10/23 N.Ishii *************************************************************/ #include #include "LCD_Lib_xc8_V1a.h" #include #pragma config FOSC = IRC, PLLEN = ON, FCMEN = OFF #pragma config IESO = OFF, USBDIV = OFF, CPUDIV = NOCLKDIV #pragma config PWRTEN = OFF, BOREN = OFF, WDTEN = OFF #pragma config HFOFST = OFF, MCLRE = ON #pragma config STVREN = ON, BBSIZ = OFF, LVP = OFF #pragma config XINST = OFF #pragma config CP0 = OFF, CP1 = OFF, CPB = OFF #pragma config WRT0 = OFF, WRT1 = OFF, WRTB = OFF, WRTC = OFF #pragma config EBTR0 = OFF, EBTR1 = OFF, EBTRB = OFF /// Message char MsgZeroAdj[]= "Zero Adjustment"; char MsgCAL[]= "Calibration"; /// SWポート定義 #define TARE_SW PORTBbits.RB7 // SW1:CAL END 兼用 #define g_plus_SW PORTBbits.RB6 // SW2:CAL START 兼用 #define g_muinus_SW PORTBbits.RB5 // SW3 /// adポート・ピン定義 #define Hx711_clk LATAbits.LATA4 #define Hx711_dat PORTAbits.RA5 /// ADデータ関係 long Hx711ad; // HX711から取り出した生のA/Dデータ long Hx711avg; // HX711のA/D値を移動平均した値 long Average[16]; // 移動平均用バッファ char Avgpoi= 0; // 移動平均のポインタ long Avgsum= 0; // 移動平均の合計値 long Zeroadj; // ゼロ調整の差分値 char Stablecount; // 安定マーク表示までのカウント数 long Lastvalue; // 前回の測定値 unsigned int Sensorcal; // ロードセル・センサーからグラム換算する校正値 char Temp1; // 汎用テンポラリ変数 Byte型 No.1 char Temp2; // 汎用テンポラリ変数 Byte型 No.2 long Templ1; // 汎用テンポラリ変数 Long型 No.1 char buf[5]; // 重量値及び校正値表示用バッファ char buf_hex[8]; // AD変換値16進表示用バッファ unsigned char Up_Byte; unsigned char Lo_Byte; //char i; //******************* プロトタイプ *********************************** void Hx711get(void); void Hx711movavg(void); void waight_val_disp(void); void TARE_SW_Read(void); void CAL_SW_Read(void); void delay_ms (int ms); // ********** EEROM に設定する 初期値(hex書込み時のみ書込まれる) *********** __EEPROM_DATA(0x75,0x71,0,0,0,0,0,0); // 0番地:セル補正値上位バイト、1番地:セル補正値下位バイト // セル補正値デフォルト= 0x7571(30065)← 実出力が定格出力= 0.7mV/Vだった場合 // (実際校正したら、0x7DD3(32211)で合った。) /***************** * メイン関数 ******************/ void main(void) { OSCCON = 0b11111111; // 16MHz internal clock UCONbits.USBEN = 0; // USBは使用しない /// アナログ入力と併用の、RB4,5に該当する /// ANSELxビットを'0'にリセット、デジタルピンとして使用する ANSELHbits.ANS10 = 0; // RB4 digital input ANSELHbits.ANS11 = 0; // RB5 digital input TRISA= 0b00101111; // RA4(SCLK) is Output, RA5(DIN) is Input 191017 TRISB= 0b11110000; // RB4-7 is Input TRISC= 0; // RC is Output /// 内部プルアップ設定 INTCON2bits.RABPU = 0; // プルアップ許可(これが無いとプルアップされない) WPUB = 0b11110000; // RB4-7 is Pull-Up LATCbits.LATC2= 0; // LED 消灯 lcd_init(); // LCD初期化 //// 20回の測定を行い、ゼロ調整用の差分を用意する。 Hx711_clk= 0; // HX711の[PD_SCK]ピンを[L]にする。(通常動作モードにする) Avgpoi= 0; // 移動平均のポインターを初期化する。 for (Temp1= 0; Temp1 < 16; ++Temp1) Average[Temp1]= 0; // 移動平均バッファ初期化 /// EEPROM読込み Up_Byte= eeprom_read(0); Lo_Byte= eeprom_read(1); // 上位、下位バイトを、1つの16bit(ワード型)に変換しSensorcalに格納 Sensorcal= (unsigned int)Up_Byte << 8 | (unsigned int)Lo_Byte; lcd_str(MsgZeroAdj); /// 20回の測定を行い移動平均する。 for (Temp1= 0; Temp1 < 20; ++Temp1) { while(Hx711_dat != 0); // HX711の[DOUT]ピンが[L]になる(変換終了)まで待つ。 Hx711get(); // HX711のチャンネルAから128の利得でA/Dデータを取り出す。 Hx711movavg(); // HX711のA/D変換データを移動平均する。 /// 下段に、AD変換の移動平均値を16進表示する。 lcd_posyx(1,0); sprintf((char *)buf_hex,"%08lx", Hx711avg); // long変数を16進で8桁アスキー変換(ゼロサプレス) lcd_str(buf_hex); } Zeroadj= 0 - Hx711avg; // 現在の測定値からゼロ調整の差分を計算する。 Stablecount= 0; // 安定マークの表示カウント数を初期化する。 Lastvalue= 0; // 前回の測定値を初期化する。 lcd_clear(); // LCD表示をすべて消去する。 //// メイン ループ while(1) { if (!Hx711_dat) { // HX711の[DOUT]ピンが[L]になった(変換終了)か? //// 重量の測定 lcd_posyx(0,0); Hx711get(); // HX711のチャンネルAから128の利得でA/Dデータを取り出す。 sprintf((char *)buf_hex,"%08lx", Hx711ad); // long変数を16進で8桁アスキー変換(ゼロサプレス) lcd_str(buf_hex); // 上段にHX711の生のA/D値をLCDに表示する。 Hx711movavg(); // HX711のA/D変換データを移動平均する。 lcd_posyx(1,0); sprintf((char *)buf_hex,"%08lx", Hx711avg); // long変数を16進で8桁アスキー変換(ゼロサプレス) lcd_str(buf_hex); // 下段に、AD変換の移動平均値を16進表示する。 Templ1= Hx711avg + Zeroadj; // ゼロ調整の差分を計算する。(ゼロ補正したad値をテンポラリに格納) Templ1= Templ1 * 100; // グラム換算の小数点桁上げと0.1g表示のために100倍する。 Templ1= Templ1 / Sensorcal; // ロードセル・センサーのA/D値からグラム換算する。 lcd_posyx(1,9); waight_val_disp(); // 液晶に重量値を表示する。 //// 安定マーク[*]の表示 lcd_posyx(0,9); // 安定マーク表示位置を確定しておく。 if (Templ1 == Lastvalue) { // 前回の測定値との差が無いか? ++Stablecount; // 安定マーク表示までのカウント数を加算する。 if (Stablecount > 5) { // 安定マーク表示のカウント数に達したか? Stablecount= 5; lcd_data('*'); // 安定マーク[*]を表示する。 } } else { Lastvalue= Templ1; // 現在の測定値を保管する。 Stablecount= 0; // 安定マークの表示カウント数を初期化する。 lcd_data(' '); // 安定マーク[*]を消去する。 } } //// スイッチ読込み処理 __delay_ms(5); // チャッタ―回避 TARE_SW_Read(); // 風袋(TARE)SW読込み(単に表示値をゼロにする機能も含む) CAL_SW_Read(); // CAL SW読込み } } //----------------------------------------------------------------------------------------------------------- /******************************************************* * HX711のチャンネルAから128の利得でA/Dデータを取り出す * (Hx711ad = 2の補数形式24bit) ********************************************************/ void Hx711get(void) { char index; Hx711ad= 0; // AD読込み値の初期化 while(Hx711_dat != 0); // datピンが、'0'になるまで待つ。('0'で、ready) for(index= 0; index < 24; index++) { Hx711_clk= 1; __delay_us(1); /// 次のビット読込に備えて1ビット左シフト /// 最初は、0なのでシフトしても変わらずストレートに、msb:b23が確定する。 /// 次に回ってきた時には、msbが1つ左シフトしたものとorされ、b22が確定する /// 最後は、bit0が確定し、結果的に 0000 0000 xxxx xxxx xxxx xxxx xxxx xxxx の32bitのad値が変数に格納される。 Hx711ad = (Hx711ad << 1) | Hx711_dat; Hx711_clk= 0; __delay_us(1); } /// 25個目のクロックパルスを送る (次回の変換をチャンネルA・利得を128に設定する) Hx711_clk= 1; __delay_us(1); Hx711_clk= 0; __delay_us(1); if (((Hx711ad >> 23) & 0x00000001) == 1) { // A/Dの24bit値がマイナス値か? Hx711ad = Hx711ad | 0xFF000000; // 32bitのマイナス値にする。 } } /************************************************************** * HX711のA/D変換データを移動平均 (Hx711avg = 16個の移動平均) ***************************************************************/ void Hx711movavg(void) { Avgsum += Hx711ad; // 新しいデータを合算する。 Avgsum= Avgsum - Average[Avgpoi]; // 一番古いデータを減算する。 Average[Avgpoi]= Hx711ad; // 移動平均バッファーに格納する。(次の古いデータ退避) ++Avgpoi; // 移動平均ポインターを更新する。 if (Avgpoi > 15) Avgpoi= 0; Hx711avg= Avgsum/16; // 16個の移動平均を取る。 } /************************************************* * 重量値の表示 **************************************************/ void waight_val_disp(void) { sprintf((char *)buf,"%5ld", Templ1); // long変数を10進で5桁アスキー変換(符号を含める)・スペースサプレス if ((Templ1 < -9) || (Templ1 > 9)) { /// ±10〜±5000 (Templ1は、補正重量値を10倍して整数にしている。例えば、10は1が元データ) lcd_data(buf[0]); // 最上位桁:符号:プラスの時は' 'マイナスの時は、'-'(表示桁数によりその最上位桁のさらに上の桁に自動的に表示) lcd_data(buf[1]); // lcd_data(buf[2]); // lcd_data(buf[3]); // lcd_data('.'); // 小数点'.'挿入 lcd_data(buf[4]); // 最下位桁 lcd_data('g'); } else { /// これ以降の処理をしないと、例えば、0→".0"、0.1→".1"表示になってしまう。 if ((Templ1 >= 0) && (Templ1 <= 9)) { /// 0.0 〜 0.9 lcd_data(buf[0]); // 最上位桁:' ' lcd_data(buf[1]); // ' '  lcd_data(buf[2]); // ' ' lcd_data('0'); // buf[3]が' 'のところ、'0'にする。 lcd_data('.'); // 小数点'.'挿入 lcd_data(buf[4]); // 最下位桁 lcd_data('g'); } else if (Templ1 <= -1) { /// -0.1 〜 -0.9 lcd_data(buf[0]); // 最上位桁:' ' lcd_data(buf[1]); // ' '  lcd_data('-'); // buf[2]が' 'のところ、'-'にする。 lcd_data('0'); // buf[3]が'-'のところ、'0'にする。 lcd_data('.'); // 小数点'.'挿入。 lcd_data(buf[4]); // 最下位桁 lcd_data('g'); } } } ///------------------------------------------------------------------------------------------ /************************************************************************** * 風袋(TARE)SW読込み(単に表示値をゼロにする機能も含む) * ・[SW1]を押すと、現在の重量値を[0.0g]にゼロ調整。 * ・また、風袋(ふうたい)機能も同時に行える。 * ・容器の重量を差し引く場合、スケールに空容器を乗せた状態で[SW1]を押すと、 *  その重量が[0.0g]になる。 ***************************************************************************/ void TARE_SW_Read(void) { if (!TARE_SW) { Zeroadj= 0 - Hx711avg; // 現在の測定値からゼロ調整の差分を計算する。 // そしてメインの頭で、この補正値を加算して現在の測定値を[0.0g]にする。 Stablecount= 0; // 安定マークの表示カウント数を初期化する。 } } /************************************************************************** * CAL SW読込み(SW1〜3を使う。):センサーの出力誤差調整 * ・SW1:CAL END(TAREと兼用) * SW2:CAL START(グラム換算値加算兼用(重量表示は下がっていく。) * SW3:グラム換算値が減算(重量表示は上がっていく。) ***************************************************************************/ void CAL_SW_Read(void) { if (!g_plus_SW) { // グラム換算値加算SW2(ここではCALスタートSWとして使用)が押されたか? lcd_clear(); lcd_str(MsgCAL); while(!g_plus_SW); // [SW2]が離されるまで待つ。 //// 校正値調整 do { //// [SW2]校正値を加算 delay_ms(100); // 長押しで連続可変。単発でも±1になるように長目に設定 if (!g_plus_SW) { /// SW2が押され、かつcal値が上限でなければグラム換算値を加算する。 if (Sensorcal < 40000) ++Sensorcal; } /// [SW3]校正値を減算 else if (!g_muinus_SW) {/// SW3が押され、かつcal値が下限でなければグラム換算値を減算する。 if (Sensorcal > 20000) --Sensorcal; } //// 校正中の重量値・校正値(グラム換算値)表示 if (!Hx711_dat) { // HX711の[DOUT]ピンが[L]になった(変換終了)か? //// CAL(ロードセル出力レベル誤差補正)前後の、重量値と、校正値表示 Hx711get(); // HX711のチャンネルAから128の利得でA/Dデータを取り出す。 Hx711movavg(); // HX711のA/D変換データを移動平均する。 Templ1= Hx711avg + Zeroadj; // ゼロ調整の差分を計算する。(ゼロ補正したad値をテンポラリに格納) Templ1= Templ1 * 100; // グラム換算の小数点桁上げと0.1g表示のために100倍する。 Templ1= Templ1 / Sensorcal; // ロードセル・センサーのA/D値からグラム換算する。 lcd_posyx(1,3); waight_val_disp(); // 液晶に重量値を表示する。 sprintf((char *)buf,"%5u", Sensorcal); // 変数を10進で5桁アスキー変換(符号を含める)・スペースサプレス lcd_posyx(1,11); lcd_str(buf); // 補正値をLCDに表示する。 } } while(TARE_SW); // SW1:TARE SW(ここではCAL_END_SWとして使用)が押されるまでループ内を実行 ///// 押されたら以下を実行してメインに戻る。 while(!TARE_SW); // [SW1]が離されるまで待つ。 /// 校正値(16bit整数)を、上位バイト・下位バイトに分割してEEPROMに書込む。 Up_Byte= (unsigned char)(Sensorcal >> 8); Lo_Byte= (unsigned char)(Sensorcal & 0x00FF); eeprom_write(0, Up_Byte); // EEPROM 0番地 書込み eeprom_write(1, Lo_Byte); // EEPROM 1番地 書込み Stablecount= 0; // 安定マークの表示カウント数を初期化する。 lcd_clear(); } } /***************************************************** * mS 単位の遅延 * XC8の場合、Fosc=16M時、__delay()の引数の限界は、49 * それを超える遅延が必要な場合に使用。 ******************************************************/ void delay_ms (int ms){ while(ms-- > 0)__delay_ms(1); }