/********************************************************** * PIC18F14K50 * * HX711_TEST_2:ロードセル用24bitADモジュールを試す。XC8版 * 参考サイト:O-Familyさん * * <変更点:大きな文字表示に拘ってみた。> *  (1) 液晶を、超小型グラフィック液晶「AQM1248A」に変更して *    4倍文字で、重量値を表示。 *  (2) AD変換値の表示は、やめる。 *  (3) 各モードのタイトル表示も、やめる。 *  (4) 校正画面は、重量値とグラム換算値のみの表示にする。 * * * ロードセル:SC616C-500g(シングルポイント・ビーム型) *       定格荷重= 500g *       定格出力= 0.7mV/V±0.15mV/V * * 内蔵発振器:16MHz使用 * Tcy= 1/(16M/4)= 250nS * * * 初期作成日:2019/11/29 N.Ishii *************************************************************/ #include #include "spi_glcd.h" #include "font.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.RB4 // 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_disp[6]; // 重量値及び校正値表示バッファ unsigned char Up_Byte; unsigned char Lo_Byte; //char i; //******************* プロトタイプ *********************************** void Hx711get(void); void Hx711movavg(void); void waight_val_disp(char,char,char); 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= 0b10110000; // RB4,5,7 is Input RB6(SCKとして使用) is Output TRISC= 0; // RC is Output /// 内部プルアップ設定 INTCON2bits.RABPU = 0; // プルアップ許可(これが無いとプルアップされない) WPUB = 0b10110000; // RB4,5,7 is Pull-Up LATCbits.LATC2= 0; // LED 消灯 mInitLCD_IO (); // LCD制御用I/O 設定 mInitSPI(); // SPI Mode II 設定 LCD_int(); clear(); //// 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; /// 20回の測定を行い移動平均する。 for (Temp1= 0; Temp1 < 20; ++Temp1) { while(Hx711_dat != 0); // HX711の[DOUT]ピンが[L]になる(変換終了)まで待つ。 Hx711get(); // HX711のチャンネルAから128の利得でA/Dデータを取り出す。 Hx711movavg(); // HX711のA/D変換データを移動平均する。 } Zeroadj= 0 - Hx711avg; // 現在の測定値からゼロ調整の差分を計算する。 Stablecount= 0; // 安定マークの表示カウント数を初期化する。 Lastvalue= 0; // 前回の測定値を初期化する。 //// メイン ループ while(1) { if (!Hx711_dat) { // HX711の[DOUT]ピンが[L]になった(変換終了)か? //// 重量の測定 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値からグラム換算する。 waight_val_disp(0,1,4); // 液晶に重量値を表示する。 //// 安定マーク用LED表示 if (Templ1 == Lastvalue) { // 前回の測定値との差が無いか? ++Stablecount; // 安定マーク表示までのカウント数を加算する。 if (Stablecount > 5) { // 安定マーク表示のカウント数に達したか? Stablecount= 5; LATCbits.LATC2= 1; // LED 点灯 } } else { Lastvalue= Templ1; // 現在の測定値を保管する。 Stablecount= 0; // 安定マークの表示カウント数を初期化する。 LATCbits.LATC2= 0; // LED 消灯 } } //// スイッチ読込み処理 __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(char x, char y, char bai) { sprintf((char *)buf,"%5ld", Templ1); // long変数を10進で5桁アスキー変換(符号を含める)・スペースサプレス if ((Templ1 < -9) || (Templ1 > 9)) { /// ±10〜±5000 buf_disp[0]= buf[0]; // 最上位桁 buf_disp[1]= buf[1]; buf_disp[2]= buf[2]; buf_disp[3]= buf[3]; buf_disp[4]= '.'; // 小数点'.'挿入 buf_disp[5]= buf[4]; // 最下位桁 LCD_str(buf_disp, x,y, bai); // *倍文字表示 } else { /// これ以降の処理をしないと、例えば、0→".0"、0.1→".1"表示になってしまう。 if ((Templ1 >= 0) && (Templ1 <= 9)) { /// 0 〜 9 buf_disp[0]= buf[0]; buf_disp[1]= buf[1]; buf_disp[2]= buf[2]; buf_disp[3]= '0'; buf_disp[4]= '.'; buf_disp[5]= buf[4]; LCD_str(buf_disp, x,y, bai); } else { /// -1 〜 -9 buf_disp[0]= buf[0]; buf_disp[1]= buf[1]; buf_disp[2]= '-'; buf_disp[3]= '0'; buf_disp[4]= '.'; buf_disp[5]= buf[4]; LCD_str(buf_disp, x,y, bai); } } } ///------------------------------------------------------------------------------------------ /************************************************************************** * 風袋(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として使用)が押されたか? clear(); 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値からグラム換算する。 waight_val_disp(32,0,3); // 液晶に重量値を表示する。3倍文字 sprintf((char *)buf,"%5u", Sensorcal); // 変数を10進で5桁アスキー変換(符号を含める)・スペースサプレス LCD_str(buf, 40,3, 3); // 補正値をLCDに表示する。3倍文字 } } 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; // 安定マークの表示カウント数を初期化する。 clear(); } } /***************************************************** * mS 単位の遅延 * XC8の場合、Fosc=16M時、__delay()の引数の限界は、49 * それを超える遅延が必要な場合に使用。 ******************************************************/ void delay_ms (int ms){ while(ms-- > 0)__delay_ms(1); }