Необхідно:
1. Arduino контролер (Nano, UNO ...)
2. LED module -індикатор
3. HX711 - модуль обробки даних тензодатчиків
4. Модуль - радіопередавач даних 433MHz TX
Принцип вимірювання ваги досить простий: навантаження змінює опір тензодатчиков, що закономірно виливається в зміну напруги на виході моста. Причому напруга змінюється лінійно залежно від ваги. Загалом, все добре, якби не одне але: вихідна напруга моста занадто мала, щоб вимірювати його безпосередньо АЦП Arduino. Для успіху необхідний відповідний підсилювач - з досить великим коефіцієнтом посилення, з досить малим шумом.
Це і є модуль HX711 Підключення тензодатчиків до модуля цифрового перетворювача HX711
Фактично цей модуль є АЦП з підсилювачем
Код: Виділити все
#include <Arduino.h>
#include <TM1637Display.h>
#include <HX711.h>
#include <VirtualWire.h>
#include <EEPROM.h>
//
#define DISPLAY_CLK 2 // digital pin connected to display
#define DISPLAY_DIO 3 // digital pin connected to display
#define BUTTON_MINUS_PIN 6 // digital pin connected to button
#define BUTTON_PLUS_PIN 7 // digital pin connected to button
#define SOUND_PIN 11 // digital pin connected to sound buzzer
#define RF_TX_PIN 12 // digital pin connected to RF TX 433 MHz
//
#define NumTimesIdle 5
#define NumTimesMeasure 15
//
const uint8_t SEG_CLEAR[] = {0,0,0,0};
const uint8_t SEG_DELIM[] = {SEG_G};
const uint8_t SEG_1[] = { SEG_C | SEG_D | SEG_E | SEG_G,
SEG_A | SEG_B | SEG_F | SEG_G,
SEG_C | SEG_D | SEG_E | SEG_G,
SEG_A | SEG_B | SEG_F | SEG_G };
const uint8_t SEG_2[] = { SEG_A | SEG_B | SEG_F | SEG_G,
SEG_C | SEG_D | SEG_E | SEG_G,
SEG_A | SEG_B | SEG_F | SEG_G,
SEG_C | SEG_D | SEG_E | SEG_G };
//
HX711 scale(A1, A0); // A1 - DOUT , A0 - SCK
TM1637Display display(DISPLAY_CLK, DISPLAY_DIO);
// -------------------------------------------------
// setSegments(const uint8_t segments[], uint8_t length = 4, uint8_t pos = 0);
// This function receives raw segment values as input and displays them. The segment data
// is given as a byte array, each byte corresponding to a single digit. Within each byte,
// bit 0 is segment A, bit 1 is segment B etc.
// segments - array of size @ref length containing the raw segment values
// length - number of digits to be modified
// pos - position from which to start the modification (0 - leftmost, 3 - rightmost)
// -------------------------------------------------
// showNumberDec(int num, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);
// num - number to be shown
// leading_zero - when true, leading zeros are displayed. Otherwise unnecessary digits are blank
// length - number of digits to set
// pos - position least significant digit (0 - lefttmost, 3 - leftmost)
// -------------------------------------------------
//
unsigned long LastTareCheckMillis = 0;
unsigned long LastTareCheckMillisMAX = 60000;
unsigned long LastDisplayWeightMillis = 0;
unsigned long LastDisplayWeightMillisMAX = 5000;
float CurScale = 4120.f; // default 2280.f
byte NumTimes = NumTimesIdle;
byte WeightCounter = 0;
byte MaxWeightCounter = 5;
float CurWeight = 0;
float MinWeight = 1; // kg
float FinishWeight = 0;
boolean seg_selector;
//
void setup()
{
// for RF TX
vw_set_ptt_pin(RF_TX_PIN);
vw_set_tx_pin(RF_TX_PIN);
vw_setup(2000); // Bits per sec
pinMode(BUTTON_MINUS_PIN, INPUT);
pinMode(BUTTON_PLUS_PIN, INPUT);
pinMode(SOUND_PIN, OUTPUT);
Serial.begin(9600);
Serial.println("");
Serial.println("A.V. SmartScales.");
CurScale = (float) EEPROMReadInt(0);
if (CurScale < 1000) { CurScale = 4426.f; }
Serial.print("CurScale = ");
Serial.println(CurScale,2);
ScalesInit();
LastTareCheckMillis = millis();
}
//
void loop()
{
// Check buttons
if ( digitalRead(BUTTON_PLUS_PIN) )
{
PlayTone(SOUND_PIN,4000,50);
CurScale = CurScale + 10;
Serial.print("BUTTON_PLUS. CurScale = ");
Serial.println(CurScale,2);
EEPROMWriteInt(0, int(CurScale));
display.setSegments(SEG_CLEAR); // display clear
display.showNumberDec(int(CurScale),true,4,0);
LastTareCheckMillis = millis();
LastDisplayWeightMillis = millis();
}
if ( digitalRead(BUTTON_MINUS_PIN) )
{
PlayTone(SOUND_PIN,4000,50);
CurScale = CurScale - 10;
scale.set_scale(CurScale);
Serial.print("BUTTON_MINUS. CurScale = ");
Serial.println(CurScale,2);
EEPROMWriteInt(0, int(CurScale));
display.setSegments(SEG_CLEAR); // display clear
display.showNumberDec(int(CurScale),true,4,0);
LastTareCheckMillis = millis();
LastDisplayWeightMillis = millis();
}
// Calculate weight
CurWeight = scale.get_units(NumTimes) * 1000 / CurScale;
if ( CurWeight > MinWeight )
{
NumTimes = NumTimesMeasure;
LastDisplayWeightMillis = millis();
if ( WeightCounter <= MaxWeightCounter )
{
if ( WeightCounter > 0 )
{
if ( WeightCounter < MaxWeightCounter )
{
PlayTone(SOUND_PIN, 800 + WeightCounter * 800 ,50);
display.setBrightness(WeightCounter + 10); // from 8 to 15
if (seg_selector) { display.setSegments(SEG_1); } else { display.setSegments(SEG_2); }
seg_selector = !seg_selector;
}
FinishWeight = FinishWeight + CurWeight;
}
if ( WeightCounter == MaxWeightCounter )
{
PlayTone(SOUND_PIN,4000,50); delay(50);
PlayTone(SOUND_PIN,3000,50); delay(50);
PlayTone(SOUND_PIN,4000,50);
FinishWeight = FinishWeight / (int)MaxWeightCounter;
display.setSegments(SEG_CLEAR); // display clear
display.setSegments(SEG_DELIM,1,2); // display delimiter
display.showNumberDec(int(FinishWeight),true,2,0);
display.showNumberDec(int((FinishWeight - int(FinishWeight)) * 10),true,1,3);
Serial.print(" WEIGHT = ");
Serial.println(FinishWeight,2);
SendWeight();
LastTareCheckMillis = millis();
LastDisplayWeightMillis = millis();
}
}
else { WeightCounter = (MaxWeightCounter + 1); }
WeightCounter++;
}
else
{
WeightCounter = 0;
NumTimes = NumTimesIdle;
FinishWeight = 0;
if ( millis() < LastDisplayWeightMillis ) { LastDisplayWeightMillis = millis(); } // after millis() overflow
if ( millis() - LastDisplayWeightMillis > LastDisplayWeightMillisMAX )
{
if ( LastDisplayWeightMillis != 0 ) { ScalesInit(); }
LastDisplayWeightMillis = 0;
}
if ( millis() < LastTareCheckMillis ) { LastTareCheckMillis = millis(); } // after millis() overflow
if ( millis() - LastTareCheckMillis > LastTareCheckMillisMAX )
{
if ( (CurWeight >= 0.01) || (CurWeight <= -0.01) )
{
display.setSegments(SEG_1);
Serial.println("Set tare...");
ScalesInit();
}
LastTareCheckMillis = millis();
}
} // if ( CurWeight > MinWeight )
//
Serial.println(CurWeight,3);
}
//////////////////////////////////////////////////////////////////
void PlayTone(byte tonePin, int frequency, int duration)
{
int period = 1000000L / frequency;
int pulse = period / 2;
for (long i = 0; i < duration * 1000L; i += period)
{
digitalWrite(tonePin, HIGH);
delayMicroseconds(pulse);
digitalWrite(tonePin, LOW);
delayMicroseconds(pulse);
}
}
void SendWeight()
{
////////// RF Send
char RFMessage[28];
String RFtemp;
// RFtemp = "Sgg.gg/";
// gg.gg - weight
RFtemp = "S";
RFtemp = RFtemp + int(FinishWeight) + ".";
if ( int((FinishWeight - int(FinishWeight)) * 100) > 9 )
{ RFtemp = RFtemp + int((FinishWeight - int(FinishWeight)) * 100); }
else
{ RFtemp = RFtemp + "0"; RFtemp = RFtemp + int((FinishWeight - int(FinishWeight)) * 100); }
RFtemp = RFtemp + "/";
RFtemp.toCharArray(RFMessage,RFtemp.length()+1);
int jj;
for ( jj = 0; jj < 5; jj++ )
{
delay(50);
vw_send((uint8_t *)RFMessage, strlen(RFMessage));
vw_wait_tx();
}
Serial.print("RFtemp = ");
Serial.println(RFtemp);
}
void EEPROMWriteInt(int p_address, int p_value)
// This function will write a 2 byte integer to the eeprom at the specified address and address + 1
{
byte lowByte = ((p_value >> 0) & 0xFF);
byte highByte = ((p_value >> 8) & 0xFF);
EEPROM.write(p_address, lowByte);
EEPROM.write(p_address + 1, highByte);
}
unsigned int EEPROMReadInt(int p_address)
// This function will read a 2 byte integer from the eeprom at the specified address and address + 1
{
byte lowByte = EEPROM.read(p_address);
byte highByte = EEPROM.read(p_address + 1);
if ( (((lowByte << 0) & 0xFF) == 0xFF) && (((highByte << 0) & 0xFF) == 0xFF) ) return 0;
else return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}
void ScalesInit()
{
display.setBrightness(9); // from 8 to 15
display.setSegments(SEG_CLEAR); // display clear
display.showNumberDec(0,false,1,1);
display.setSegments(SEG_DELIM,1,2); // display delimiter
display.showNumberDec(0,false,1,3);
scale.set_scale(CurScale);
scale.tare();
}