/* Arduino Uno code for reading load cells via an HX711 board and generating a 0-5 VDC output with a MCP4725 board. MCP4725 has 12-bit resolution and takes 0-4095 as an argument. Wiring: <-- HX711 to Uno --> GND -> GND CLK -> D2 (CLK) DAT -> D3 (DOUT) VDD -> 5V // can be shorted to VCC VCC -> 5V <-- Uno to MCP4725 --> GND -> GND 5V/3.3V -> VCC // 5V for connections to a 5V logic controller running BC firmware or 3.3V for connections to a 3.3V logic controller running BC firmware A4 (SDA) -> SDA A5 (SCL) -> SCL <-- MCP4725 to MEGA 2560 --> GND -> GND OUT -> Analog Input (Ax) // as per appropriate BC wiring diagram <-- DS18B20 temperature probe to Uno --> 1 (GND) -> GND 2* (Data) -> D11 (oneWireBus) 3* (VDD) -> 5V* *3 (VDD) to 2 (Data) on DS18B20 temp probe via a 4.7K ohm resistor */ #include #include #include #include #include #include // variable declarations #define CLK 2 // CLK pin assignment #define DOUT 3 // DOUT pin assignment #define oneWireBus 11 // data pin for DS18B20 temp probe #define btnRIGHT 0 #define btnUP 1 #define btnDOWN 2 #define btnLEFT 3 #define btnSELECT 4 #define btnNONE 5 bool massAppBK = false; // set to "true" for boil kettle application. Set to "false" for MLT application bool showKg = false; // set to "true" for mass values displayed in kg. Set to "false" for mass values displayed in lbs bool showC = false; // set to "true" for temp values displayed in C. Set to "false" for mass values displayed in F bool tempDebug = false; // set to "true" to enable serial output for temp. debugging purposes. Set to "false" to disable bool loadCellDebug = false; // set to "true" to enable serial output for load cell debugging purposes. Set to "fasle" to disable char outstr[DOUT]; float calibrationFactorBK = 11147.07; // set to calibration factor determined from running the HX711_ADC example sketch "Calibration". This one for the "BK" use float calibrationFactorMLT = 11280.41; // set to calibration factor determined from running the HX711_ADC example sketch "Calibration". This one for the "MLT" use float DAC_CV; float DAC_Slope; int DAC_Min = 0; // set to DAC min value (0 for MCP4725) int DAC_Max = 4095; // set to DAC max value (4095 for MCP4725) float gallons; float loadCellsCV; float maxScaleWeightBK = 75.80; // BK max volume of xx.x gals * 3.79 kg/gal (20.0 gallons used as basis for default value) float maxScaleWeightMLT = 56.85; // MLT max volume of xx.x gals * 3.79 kg/gal (15.0 gallons used as basis for default value) float tempRawHigh = 99.9; // DS18B20 value at high calibration point float tempRawLow = 0.0; // DS18B20 value at low calibration point float tempReferenceHigh = 99.9; // actual temp value from calibrated (i.e trusted) temp. device at the high calibration point float tempReferenceLow = 0.0; // actual temp value from calibrated (i.e. trusted) temp. device at the low calibration point float tempRawRange = tempRawHigh - tempRawLow; float tempReferenceRange = tempReferenceHigh - tempReferenceLow; float tempCorrectedValueC; float tempCorrectedValueF; int tempTrend; int previousTempTrend = 0; int lcdKey = 0; int adcKeyIn = 0; int celsius; int fahrenheit; long stabilisingTime = 5000; unsigned long t; // HX711 constructor (DOUT pin, CLK pin) HX711_ADC loadCells(DOUT,CLK); // MCP4725 constructor Adafruit_MCP4725 DAC_Out; // OneWire constructor OneWire oneWire(oneWireBus); // Dallas Temp constructor DallasTemperature tempSensor(&oneWire); // LCD display constructor LiquidCrystal lcd(8, 9, 4, 5, 6, 7); int read_LCD_buttons(){ adcKeyIn = analogRead(0); if (adcKeyIn > 1000) return btnNONE; if (adcKeyIn < 50) return btnRIGHT; if (adcKeyIn < 250) return btnUP; if (adcKeyIn < 450) return btnDOWN; if (adcKeyIn < 650) return btnLEFT; if (adcKeyIn < 850) return btnSELECT; return btnNONE; } void setup(){ // initialize serial communications if (tempDebug || loadCellDebug == true){ Serial.begin(9600); delay(10); Serial.println(); Serial.println("Starting serial comms..."); } // initialize LCD display (DFRobot 1602 keypad shield) lcd.begin(16, 2); lcd.setCursor(0,0); lcd.print("Mass controller "); lcd.setCursor(0,1); lcd.print("initializing...."); delay(2000); if (tempDebug || loadCellDebug == true){ lcd.setCursor(0,0); lcd.clear(); lcd.print("Serial Debug"); lcd.setCursor(0,1); lcd.print("Enabled........."); } if (tempDebug == false && loadCellDebug == false){ lcd.clear(); lcd.print("Serial Debug"); lcd.setCursor(0,1); lcd.print("Disabled........"); } delay(500); // initialize MCP4725 DAC DAC_Out.begin(0x60); if (massAppBK == true){ DAC_Slope = (DAC_Max-DAC_Min)/maxScaleWeightBK; } if (massAppBK == false){ DAC_Slope = (DAC_Max-DAC_Min)/maxScaleWeightMLT; } // initialize HX711 amplifier loadCells.begin(); loadCells.start(stabilisingTime); lcd.setCursor(0,0); if(loadCells.getTareTimeoutFlag()){ lcd.clear(); lcd.print("Tare timed out"); if (loadCellDebug == true){ Serial.print("Tare timed out"); Serial.println(); } delay(2000); } else { if (massAppBK == true){ loadCells.setCalFactor(calibrationFactorBK); } if (massAppBK == false){ loadCells.setCalFactor(calibrationFactorMLT); } lcd.clear(); lcd.setCursor(0,0); lcd.print("Init Cal Complte"); lcd.setCursor(0,1); lcd.print("Currnt Cal:"); if (massAppBK == true){ lcd.print(calibrationFactorBK,0); } if (massAppBK == false){ lcd.print(calibrationFactorMLT,0); } if (loadCellDebug == true){ Serial.print("Initial calibration complete"); Serial.println(); Serial.print("Current Calibration Factor: "); if (massAppBK == true){ Serial.print(calibrationFactorBK,0); } if (massAppBK == false){ Serial.print(calibrationFactorMLT,0); } Serial.println(); } delay(2000); } // initialize DS18B20 temp sensor tempSensor.begin(); } // load cells, DS18B20 & lcd interface loop void loop(){ // get load cells current value (CV), print CV to LCD, convert CV to VDC, update DAC output accordingly loadCells.update(); if (millis() > t + 250){ float loadCellsRV = loadCells.getData(); // temp compensation for load cells if ((tempCorrectedValueC >= 0) && (tempCorrectedValueC <= 40)) { loadCellsCV = loadCellsRV; } if ((tempCorrectedValueC >= 41) && (tempCorrectedValueC <= 55)){ double tempC_TCA[] = {2.5,5.0,7.5,10.0,12.5,15.0,17.5,20.0,22.5,25.0,27.5,30.0,32.5,35.0,37.5}; // values here are specific for the Phidgets 50 kg bar load cell int tempC_TCAV = (tempCorrectedValueC - 41); double loadCellsCV_TC = tempC_TCA[tempC_TCAV]; if (tempTrend == 1){ loadCellsCV = loadCellsRV + (loadCellsCV_TC * 0.001); } if (tempTrend == 2){ loadCellsCV = loadCellsRV - (loadCellsCV_TC * 0.001); } } if (tempCorrectedValueC > 55){ if (tempTrend == 1){ loadCellsCV = loadCellsRV + (37.5 * 0.001); } if (tempTrend == 2){ loadCellsCV = loadCellsRV - (37.5 * 0.001); } } else { loadCellsCV = loadCellsRV; } DAC_CV = (DAC_Min + DAC_Slope) * loadCellsCV; gallons = loadCellsCV / 3.79; // ensure DAC value is always between 0 and 4095 if (DAC_CV <= DAC_Min){ DAC_CV = DAC_Min; } if (DAC_CV >= DAC_Max){ DAC_CV = DAC_Max; } DAC_Out.setVoltage(DAC_CV, false); // print CV to LCD display and serial monitor lcd.setCursor(0,0); if (massAppBK == true){ dtostrf(gallons,8,2,outstr); lcd.print("BK: "); } if (massAppBK == false){ dtostrf(gallons,7,2,outstr); lcd.print("MLT: "); } lcd.print(outstr); lcd.print(" gal "); lcd.setCursor(0,1); lcd.print("Mass: "); if (showKg == true){ float kg = loadCellsCV; dtostrf(kg,6,2,outstr); lcd.print(outstr); lcd.print(" kg "); } if (showKg == false){ float lbs = loadCellsCV * 2.205; dtostrf(lbs,6,2,outstr); lcd.print(outstr); lcd.print(" lbs "); } if (loadCellDebug == true){ if (millis() > t + 1000){ Serial.print("Load cells current value: "); Serial.print(loadCellsCV,2); Serial.print(" kg |"); Serial.print(outstr); Serial.print(" gal |"); Serial.print(" DAC value: "); Serial.print(DAC_CV,1); Serial.println(); } } t = millis(); } // request DS18B20 temp value if (millis() > t + 20000){ tempSensor.requestTemperatures(); fahrenheit = tempSensor.getTempFByIndex(0); celsius = tempSensor.getTempCByIndex(0); tempCorrectedValueC = (((celsius - tempRawLow) * tempReferenceRange)/tempRawRange) + tempReferenceLow; tempCorrectedValueF = ((((celsius - tempRawLow) * tempReferenceRange)/tempRawRange) + tempReferenceLow) * 1.8 + 32; if (tempDebug == true){ Serial.print("Temperature -> "); Serial.print("Raw: "); Serial.print(fahrenheit); Serial.print("F |"); Serial.print(" Corrected: "); Serial.print(tempCorrectedValueF,1); Serial.print("F"); Serial.print(" || Raw: "); Serial.print(celsius); Serial.print("C |"); Serial.print(" Corrected: "); Serial.print(tempCorrectedValueC,1); Serial.print("C "); Serial.println(); } } // determine DB18B20 temperature trend if (millis() > t + 30000){ float currentTempC = tempCorrectedValueC; float previousTempC; float tempDelta; if (currentTempC != previousTempC){ tempDelta = currentTempC - previousTempC; } if (tempDelta > 0){ tempTrend = 2; // temp is increasing } else if (tempDelta < 0){ tempTrend = 1; // temp is decreasing } else{ tempTrend = 0; // temp is steady } previousTempC = currentTempC; } lcdKey = read_LCD_buttons(); switch (lcdKey){ case btnRIGHT:{ // manual tare function loadCells.tareNoDelay(); lcd.setCursor(0,0); lcd.print("Tare started...."); delay(2000); if(loadCells.getTareStatus() == true) { lcd.setCursor(0,0); lcd.print("Tare error! "); delay(2000); } else { lcd.setCursor(0,0); lcd.print("Tare complete...."); delay(1000); } break; } case btnUP:{ // manual (+) calibration value adjustment if (massAppBK == true){ calibrationFactorBK += 10; } if (massAppBK == false){ calibrationFactorMLT += 10; } delay(500); lcd.setCursor(0,1); lcd.print("Cal Up: "); if (massAppBK == true){ lcd.print(calibrationFactorBK,0); } if (massAppBK == false){ lcd.print(calibrationFactorMLT,0); } delay(500); break; } case btnDOWN:{ // manual (-) calibration value adjustment if (massAppBK == true){ calibrationFactorBK -= 10; } if (massAppBK == false){ calibrationFactorMLT -= 10; } delay(500); lcd.setCursor(0,1); lcd.print("Cal Dn: "); if (massAppBK == true){ lcd.print(calibrationFactorBK,0); } if (massAppBK == false){ lcd.print(calibrationFactorMLT,0); } delay(500); break; } case btnLEFT:{ // print DS18B20 temp value to LCD display tempSensor.requestTemperatures(); fahrenheit = tempSensor.getTempFByIndex(0); celsius = tempSensor.getTempCByIndex(0); tempCorrectedValueC = (((celsius - tempRawLow) * tempReferenceRange)/tempRawRange) + tempReferenceLow; tempCorrectedValueF = ((((celsius - tempRawLow) * tempReferenceRange)/tempRawRange) + tempReferenceLow) * 1.8 + 32; lcd.setCursor(0,1); lcd.print("Temp: "); if (showC == true){ lcd.print(tempCorrectedValueC,1); lcd.print(" C "); } if (showC == false){ lcd.print(tempCorrectedValueF,1); lcd.print(" F "); } delay(1500); break; } case btnSELECT:{ // manual calibration function lcd.setCursor(0,0); lcd.print("Cal Started....."); loadCells.start(stabilisingTime); if (massAppBK == true){ loadCells.setCalFactor(calibrationFactorBK); } if (massAppBK == false){ loadCells.setCalFactor(calibrationFactorMLT); } delay(1000); lcd.setCursor(0,0); lcd.print("Cal Val Written "); lcd.setCursor(0,1); lcd.print("Currnt Cal:"); if (massAppBK == true){ lcd.print(calibrationFactorBK,0); } if (massAppBK == false){ lcd.print(calibrationFactorMLT,0); } delay(500); break; } case btnNONE:{ break; } } }