#include "HX711.h" // ไลบรารีสำหรับสื่อสารกับโหลดเซลล์ผ่านโมดูล HX711
#include <LiquidCrystal_I2C.h> // ไลบรารีสำหรับควบคุมหน้าจอ LCD แบบ I2C
#include <Keypad.h>
#include <TFT.h> // Arduino LCD library
#include <SPI.h>
#define cs 46
#define dc 48
#define rst 47
// SCL / SCL -> GPIO 52
// SDA / MOSI -> GPIO 51
const byte KEYPAD_ROWS = 4; // จำนวนแถว
const byte KEYPAD_COLS = 4; // จำนวนคอลัมน์
// กำหนดพินที่ใช้สำหรับแถวและคอลัมน์
byte rowPins[KEYPAD_ROWS] = {30, 31, 32, 33}; // กำหนดขาแถว
byte colPins[KEYPAD_COLS] = {34, 35, 36, 37}; // กำหนดขาคอลัมน์
// กำหนดปุ่มของ Keypad
char keys[KEYPAD_ROWS][KEYPAD_COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
// สร้างออบเจ็กต์ Keypad
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEYPAD_ROWS, KEYPAD_COLS);
TFT TFTscreen = TFT(cs, dc, rst);
// Pin definitions: กำหนดขาของ Arduino ที่เชื่อมต่อกับโหลดเซลล์แต่ละตัว
const int LOADCELL_DOUT_PIN1 = 13; // ขา DOUT ของโหลดเซลล์ตัวที่ 1
const int LOADCELL_SCK_PIN1 = 12; // ขา SCK ของโหลดเซลล์ตัวที่ 1
const int LOADCELL_DOUT_PIN2 = 11; // ขา DOUT ของโหลดเซลล์ตัวที่ 2
const int LOADCELL_SCK_PIN2 = 10; // ขา SCK ของโหลดเซลล์ตัวที่ 2
const int LOADCELL_DOUT_PIN3 = 9; // ขา DOUT ของโหลดเซลล์ตัวที่ 3
const int LOADCELL_SCK_PIN3 = 8; // ขา SCK ของโหลดเซลล์ตัวที่ 3
const int LOADCELL_DOUT_PIN4 = 4; // ขา DOUT ของโหลดเซลล์ตัวที่ 4
const int LOADCELL_SCK_PIN4 = 3; // ขา SCK ของโหลดเซลล์ตัวที่ 4
const int LOADCELL_DOUT_PIN5 = 5; // ขา DOUT ของโหลดเซลล์ตัวที่ 5
const int LOADCELL_SCK_PIN5 = 6; // ขา SCK ของโหลดเซลล์ตัวที่ 5
// LED Pins: กำหนดขาของ Arduino ที่เชื่อมต่อกับ LED สำหรับแสดงสถานะของเครื่องชั่ง
const int LED_GREEN_PIN1 = 22; // หลอดไฟสีเขียวสำหรับเครื่องชั่งที่ 1
const int LED_RED_PIN1 = 23; // หลอดไฟสีแดงสำหรับเครื่องชั่งที่ 1
const int LED_GREEN_PIN2 = 24; // หลอดไฟสีเขียวสำหรับเครื่องชั่งที่ 2
const int LED_RED_PIN2 = 25; // หลอดไฟสีแดงสำหรับเครื่องชั่งที่ 2
const int LED_GREEN_PIN3 = 26; // หลอดไฟสีเขียวสำหรับเครื่องชั่งที่ 3
const int LED_RED_PIN3 = 27; // หลอดไฟสีแดงสำหรับเครื่องชั่งที่ 3
const int LED_GREEN_PIN4 = 28; // หลอดไฟสีเขียวสำหรับเครื่องชั่งที่ 4
const int LED_RED_PIN4 = 29; // หลอดไฟสีแดงสำหรับเครื่องชั่งที่ 4
String inputBuffer = "";
String flaxkeyped = "0"; // หลอดไฟสีแดงสำหรับเครื่องชั่งที่ 4
// สร้างตัวแปร scale สำหรับโหลดเซลล์แต่ละตัว
HX711 scale1, scale2, scale3, scale4, scale5;
// กำหนด calibration factor สำหรับการคำนวณน้ำหนักของแต่ละเครื่องชั่ง
//float calibration_factor1 = 99000;
//float calibration_factor2 = 430000;
//float calibration_factor3 = 430000;
//float calibration_factor4 = 454000;
//float calibration_factor5 = 454000;
float calibration_factor1 = 420;
float calibration_factor2 = 420;
float calibration_factor3 = 420;
float calibration_factor4 = 420;
float calibration_factor5 = 420;
// ตัวแปรสำหรับเก็บค่าน้ำหนักจากเครื่องชั่งแต่ละตัว และน้ำหนักที่เหลืออยู่
float weight1 = 0, weight2 = 0, weight3 = 0, weight4 = 0, weight5 = 0;
float remaining_weight = 0;
// ตัวแปรสำหรับเก็บค่าน้ำหนักของเครื่องชั่งแต่ละตัวในรูปแบบอาเรย์
int scales1[] = {0, 0, 0, 0};
int setpoint = 8; // กำหนดน้ำหนักเป้าหมายที่ต้องการ
// ฟังก์ชันสำหรับควบคุมการแสดงผลของ LED ตามสถานะการใช้งานของเครื่องชั่ง
void displayScalesStatus(bool used_indices[]) {
// เครื่องชั่ง 2
digitalWrite(LED_GREEN_PIN1, used_indices[0] ? HIGH : LOW); // เปิดไฟเขียวถ้าเครื่องชั่งถูกใช้
digitalWrite(LED_RED_PIN1, !used_indices[0] ? HIGH : LOW); // เปิดไฟแดงถ้าเครื่องชั่งไม่ได้ถูกใช้
// เครื่องชั่ง 3
digitalWrite(LED_GREEN_PIN2, used_indices[1] ? HIGH : LOW);
digitalWrite(LED_RED_PIN2, !used_indices[1] ? HIGH : LOW);
// เครื่องชั่ง 4
digitalWrite(LED_GREEN_PIN3, used_indices[2] ? HIGH : LOW);
digitalWrite(LED_RED_PIN3, !used_indices[2] ? HIGH : LOW);
// เครื่องชั่ง 5
digitalWrite(LED_GREEN_PIN4, used_indices[3] ? HIGH : LOW);
digitalWrite(LED_RED_PIN4, !used_indices[3] ? HIGH : LOW);
}
// ฟังก์ชันสำหรับแสดงสถานะการใช้งานของเครื่องชั่งบน Serial Monitor
void displayScalesStatus1(int scales[], int n, bool used_indices[]) {
Serial.println(); // พิมพ์บรรทัดว่างเพื่อความชัดเจน
for (int i = 0; i < n; i++) {
if (used_indices[i]) {
Serial.print("Scale ");
Serial.print(i + 1);
Serial.print(": หลอดไฟสีเขียว (ใช้), น้ำหนัก: ");
Serial.print(scales[i]);
Serial.println(" kg");
} else {
Serial.print("Scale ");
Serial.print(i + 1);
Serial.print(": หลอดไฟสีแดง (ไม่ใช้), น้ำหนัก: ");
Serial.print(scales[i]);
Serial.println(" kg");
}
}
}
void setup() {
Serial.begin(9600); // เริ่มต้นการสื่อสารผ่าน Serial Monitor
// เริ่มต้นการทำงานของเครื่องชั่งแต่ละตัว
scale1.begin(LOADCELL_DOUT_PIN1, LOADCELL_SCK_PIN1);
scale2.begin(LOADCELL_DOUT_PIN2, LOADCELL_SCK_PIN2);
scale3.begin(LOADCELL_DOUT_PIN3, LOADCELL_SCK_PIN3);
scale4.begin(LOADCELL_DOUT_PIN4, LOADCELL_SCK_PIN4);
scale5.begin(LOADCELL_DOUT_PIN5, LOADCELL_SCK_PIN5);
// ตั้งค่า calibration factor และ reset เครื่องชั่ง (tare)
scale1.set_scale(calibration_factor1);
scale1.tare();
scale2.set_scale(calibration_factor2);
scale2.tare();
scale3.set_scale(calibration_factor3);
scale3.tare();
scale4.set_scale(calibration_factor4);
scale4.tare();
scale5.set_scale(calibration_factor5);
scale5.tare();
// กำหนดขาของ LED เป็น output
pinMode(LED_GREEN_PIN1, OUTPUT);
pinMode(LED_RED_PIN1, OUTPUT);
pinMode(LED_GREEN_PIN2, OUTPUT);
pinMode(LED_RED_PIN2, OUTPUT);
pinMode(LED_GREEN_PIN3, OUTPUT);
pinMode(LED_RED_PIN3, OUTPUT);
pinMode(LED_GREEN_PIN4, OUTPUT);
pinMode(LED_RED_PIN4, OUTPUT);
TFTscreen.begin();
TFTscreen.background(0, 0, 0);
TFTscreen.stroke(255, 255, 255);
TFTscreen.setTextSize(1);
String message = "Key SetPoint >>>> D : " + inputBuffer ;
TFTscreen.text(message.c_str(), 10, 5);
}
void loop() {
char key = keypad.getKey(); // อ่านค่าปุ่มที่กด
if (key) { // ถ้ากดปุ่ม
if (key == 'D') { // ถ้ากดปุ่มเคลียร์
flaxkeyped = "1";
String message = "Setpoint : " + inputBuffer;
TFTscreen.background(0, 0, 0); // ตั้งค่าพื้นหลังสีดำ
TFTscreen.text(message.c_str(), 10, 20);
setpoint = inputBuffer.toInt();
inputBuffer = ""; // ล้างข้อมูลใน buffer
Serial.println("Cleared!");
} else if (key == '*') { // แทนที่ * ด้วย .
inputBuffer += '.';
TFTscreen.background(0, 0, 0); // ตั้งค่าพื้นหลังสีดำ
String message = "Key SetPoint >>>> D : " + inputBuffer;
TFTscreen.text(message.c_str(), 10, 5);
Serial.println(inputBuffer);
String message1 = "Setpoint : " + inputBuffer;
TFTscreen.text(message1.c_str(), 10, 20);
} else if (key == 'A') { // กดปุ่ม Backspace
if (inputBuffer.length() > 0) { // ถ้า buffer ไม่ว่าง
inputBuffer.remove(inputBuffer.length() - 1); // ลบตัวสุดท้าย
}
TFTscreen.background(0, 0, 0); // ตั้งค่าพื้นหลังสีดำ
String message = "Key SetPoint >>>> D : " + inputBuffer;
TFTscreen.text(message.c_str(), 10, 5);
Serial.println(inputBuffer);
String message1 = "Setpoint : " + inputBuffer;
TFTscreen.text(message1.c_str(), 10, 20);
} else { // เพิ่มค่าที่กดไปใน buffer
TFTscreen.background(0, 0, 0); // ตั้งค่าพื้นหลังสีดำ
String message = "Key SetPoint >>>> D : " + inputBuffer;
TFTscreen.text(message.c_str(), 10, 5);
flaxkeyped = "0";
inputBuffer += key;
Serial.println(inputBuffer); // แสดงค่าปัจจุบัน
String message1 = "Setpoint : " + inputBuffer;
TFTscreen.text(message1.c_str(), 10, 20);
}
}
if (flaxkeyped == "1"){
//TFTscreen.text("Raw Load cell ", 10, 5);
// อ่านน้ำหนักจากเครื่องชั่งแต่ละตัว
weight1 = scale1.get_units(10); // น้ำหนักจากเครื่องชั่งที่ 1
weight2 = scale2.get_units(10); // น้ำหนักจากเครื่องชั่งที่ 2
weight3 = scale3.get_units(10); // น้ำหนักจากเครื่องชั่งที่ 3
weight4 = scale4.get_units(10); // น้ำหนักจากเครื่องชั่งที่ 4
weight5 = scale5.get_units(10); // น้ำหนักจากเครื่องชั่งที่ 5
// บันทึกน้ำหนักเครื่องชั่ง 2-4 ลงในอาเรย์
scales1[0] = weight2;
scales1[1] = weight3;
scales1[2] = weight4;
scales1[3] = weight5;
// ตั้งค่าน้ำหนักที่อ่านได้ให้เป็น 0 ถ้าน้ำหนักเป็นลบ
if (weight1 < 0) weight1 = 0;
if (weight2 < 0) weight2 = 0;
if (weight3 < 0) weight3 = 0;
if (weight4 < 0) weight4 = 0;
if (weight5 < 0) weight5 = 0;
// คำนวณน้ำหนักรวมจากทุกเครื่องชั่ง
float total_weight = weight1 + weight2 + weight3 + weight4 + weight5;
float total_weight1 = weight2 + weight3 + weight4 + weight5;
// คำนวณน้ำหนักที่เหลือที่ต้องการ
remaining_weight = setpoint - total_weight;
char buffer[10]; // สร้างบัฟเฟอร์สำหรับเก็บข้อความ (ขนาดที่เหมาะสมกับข้อความของคุณ)
// เคลียร์หน้าจอ
TFTscreen.background(0, 0, 0); // ตั้งค่าพื้นหลังสีดำ
// แสดง Total
String weightStr = String(total_weight, 2);
String message = "Total: " + weightStr + " kg";
String weightStr2 = String(remaining_weight, 2);
String message2 = "Remaining: " + weightStr2 + " kg";
String weightStr3 = String(weight1, 2);
String message3 = "Scale 1: " + weightStr3 + " kg";
String weightStr4 = String(weight2, 2);
String message4 = "Scale 2: " + weightStr4 + " kg";
String weightStr5 = String(weight3, 2);
String message5 = "Scale 3: " + weightStr5 + " kg";
String weightStr6 = String(weight4, 2);
String message6 = "Scale 4: " + weightStr6 + " kg";
String weightStr7 = String(weight5, 2);
String message7 = "Scale 5: " + weightStr7 + " kg";
TFTscreen.text(message.c_str(), 10, 5);
TFTscreen.text(message2.c_str(), 10, 20);
TFTscreen.text(message3.c_str(), 10, 40);
TFTscreen.text(message4.c_str(), 10, 60);
TFTscreen.text(message5.c_str(), 10, 80);
TFTscreen.text(message6.c_str(), 10, 100);
TFTscreen.text(message7.c_str(), 10, 115);
Serial.println(message);
Serial.println(message2);
Serial.println(message3);
Serial.println(message4);
Serial.println(message5);
Serial.println(message6);
Serial.println(message7);
// สร้างอาเรย์เก็บสถานะการใช้งานของเครื่องชั่ง
bool used_indices1[4] = {false, false, false, false};
// ตรวจสอบว่ามีชุดเครื่องชั่งที่ตรงกับน้ำหนักที่ขาดหายไปหรือไม่
if (findScalesCombination(setpoint - weight1, scales1, 4, used_indices1)) {
displayScalesStatus(used_indices1); // ควบคุมการแสดงผลของ LED
displayScalesStatus1(scales1, 4, used_indices1); // แสดงสถานะใน Serial Monitor
} else {
Serial.println("ไม่พบชุดของเครื่องชั่งที่มีน้ำหนักรวมตรงกับน้ำหนักที่ขาดหายไป");
// ถ้าไม่มีชุดเครื่องชั่งที่ตรงกับน้ำหนักที่ขาดหายไป ให้เปิดไฟแดงทุกเครื่องชั่ง
digitalWrite(LED_GREEN_PIN1, LOW);
digitalWrite(LED_RED_PIN1, HIGH);
digitalWrite(LED_GREEN_PIN2, LOW);
digitalWrite(LED_RED_PIN2, HIGH);
digitalWrite(LED_GREEN_PIN3, LOW);
digitalWrite(LED_RED_PIN3, HIGH);
digitalWrite(LED_GREEN_PIN4, LOW);
digitalWrite(LED_RED_PIN4, HIGH);
}
Serial.println(); // พิมพ์บรรทัดว่างเพื่อความชัดเจน
}
}
// ฟังก์ชันสำหรับหาชุดเครื่องชั่งที่ตรงกับน้ำหนักที่ขาดหายไป
bool findScalesCombination(int target_weight, int scales[], int n, bool used_indices[]) {
for (int i = 0; i < (1 << n); i++) { // ลองทุกชุดค่าผสมของเครื่องชั่ง
int total_weight1 = 0;
for (int j = 0; j < n; j++) {
if (i & (1 << j)) { // ถ้าบิตที่ j ถูกตั้งค่า ให้รวมเครื่องชั่งนั้นในผลรวม
total_weight1 += scales[j];
}
}
if (abs(total_weight1 - target_weight) < 1e-8) { // ถ้าผลรวมตรงกับน้ำหนักที่ต้องการ
for (int j = 0; j < n; j++) {
used_indices[j] = (i & (1 << j)) != 0; // ตั้งค่าสถานะเครื่องชั่งที่ถูกใช้
}
return true; // เจอชุดที่ตรงกับน้ำหนักเป้าหมาย
}
}
return false; // ไม่เจอชุดเครื่องชั่งที่ตรงกับน้ำหนักเป้าหมาย
}