Pārlūkot izejas kodu

init commit

master
Martin Hatina pirms 3 mēnešiem
revīzija
4a75f0e565
16 mainītis faili ar 807 papildinājumiem un 0 dzēšanām
  1. +2
    -0
      .gitignore
  2. +39
    -0
      include/README
  3. +46
    -0
      lib/README
  4. +18
    -0
      platformio.ini
  5. +60
    -0
      src/buttons.cpp
  6. +30
    -0
      src/buttons.h
  7. +89
    -0
      src/lcd.cpp
  8. +27
    -0
      src/lcd.h
  9. +92
    -0
      src/main.cpp
  10. +43
    -0
      src/scale.cpp
  11. +80
    -0
      src/scale.h
  12. +119
    -0
      src/serial.cpp
  13. +29
    -0
      src/serial.h
  14. +45
    -0
      src/weight_controller.cpp
  15. +77
    -0
      src/weight_controller.h
  16. +11
    -0
      test/README

+ 2
- 0
.gitignore Parādīt failu

@@ -0,0 +1,2 @@
.pio
.vscode

+ 39
- 0
include/README Parādīt failu

@@ -0,0 +1,39 @@

This directory is intended for project header files.

A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.

```src/main.c

#include "header.h"

int main (void)
{
...
}
```

Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.

In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.

Read more about using header files in official GCC documentation:

* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes

https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

+ 46
- 0
lib/README Parādīt failu

@@ -0,0 +1,46 @@

This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.

The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").

For example, see a structure of the following two libraries `Foo` and `Bar`:

|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c

and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>

int main (void)
{
...
}

```

PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.

More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

+ 18
- 0
platformio.ini Parādīt failu

@@ -0,0 +1,18 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:nanoatmega328new]
platform = atmelavr
board = nanoatmega328
framework = arduino
lib_deps =
bogde/HX711@^0.7.4
marcoschwartz/LiquidCrystal_I2C@^1.1.4
thijse/EEPROMEx@0.0.0-alpha+sha.09d7586108

+ 60
- 0
src/buttons.cpp Parādīt failu

@@ -0,0 +1,60 @@
#include "buttons.h"
#include "lcd.h"
#include "scale.h"

void Buttons::init() {
pinMode(tare_button, INPUT);
pinMode(controller_button, INPUT);
pinMode(plus_button, INPUT);
pinMode(minus_button, INPUT);
}

bool Buttons::is_any_pressed() {
return digitalRead(tare_button) || digitalRead(controller_button);
}

void Buttons::on_button_pressed(Scale& scale, WeightControllerPool& pool, const LCD& lcd) {
Action buttonAction = get_button_action();
switch (buttonAction) {
case Action::TAR:
scale.tare();
break;
case Action::CALIBRATE:
scale.calibrate();
break;
case Action::NEXT_CONTROLLER:
lcd.clear();
pool.next();
break;
default:
break;
}
}

Buttons::Action Buttons::get_button_action() {
int button_pressed = 0;
for (int i = 0; i < buttons_count; i++) {
button_pressed |= digitalRead(buttons[i]) < i;
}

if (last_pressed == button_pressed) {

}

Buttons::Action action;
if (button_pressed & 0x0001) {
action = Action::TAR;
}
else if (tare_pressed && !controller_pressed) {
action = Action::NEXT_CONTROLLER;
}
else {
action = Action::NONE;
}

if (action == Action::TAR && (now - then) > 2000) {
action = Action::CALIBRATE;
}

return action;
}

+ 30
- 0
src/buttons.h Parādīt failu

@@ -0,0 +1,30 @@
#ifndef BUTTONS_H
#define BUTTONS_H

#include <Arduino.h>
#include "lcd.h"
#include "scale.h"
#include "weight_controller.h"

#define tare_button A0
#define controller_button A1
#define plus_button A2
#define minus_button A3

class Buttons {
private:
enum class Action {
NONE,
TAR,
CALIBRATE,
NEXT_CONTROLLER
};

public:
void init();
bool is_any_pressed();
void on_button_pressed(Scale &scale, WeightControllerPool &pool, const LCD &lcd);
Buttons::Action get_button_action();
};

#endif

+ 89
- 0
src/lcd.cpp Parādīt failu

@@ -0,0 +1,89 @@
#include "lcd.h"

LCD::LCD() {}

LCD::~LCD() {
delete lcd;
}

void LCD::init() {
lcd = new LiquidCrystal_I2C(0x27, columns, rows);
lcd->init();
lcd->backlight();
lcd->setBacklight(HIGH);
}

void LCD::print_init_message(int calibration_weight) const {
lcd->setCursor(0, 0);
lcd->print(F("YCM Scale"));
lcd->setCursor(0, 1);
lcd->print(F("Scaled to: "));
lcd->print(calibration_weight);
lcd->print(F("g"));
delay(1500);
}

void LCD::print_calibration(int calib_weight) const {
lcd->setCursor(0, 1);
lcd->print("Calibration: ");
lcd->print(calib_weight);
lcd->print(" g");
delay(800);
clear_row(1);
}

void LCD::print_weight(double weight, int precision, const char* unit) const {
//
// MAKE SURE NEGATIVE AND POSITIVE VALUES DON'T JUMP
//
if (weight > 0) {
lcd->print(" ");
}

//
// PRINT
//
lcd->print(weight, precision);
lcd->print(" ");
lcd->print(unit);
}

void LCD::print_weights(double grams, double grains) const {
lcd->setCursor(0, 0);
print_weight(grams, 3, "g ");
lcd->setCursor(0, 1);
print_weight(grains, 2, "grn ");
}

void LCD::print_control_result(String name, double val_min, double val_max, int result) {
lcd->setCursor(0, 0);
lcd->print(name);
lcd->print(" ");
lcd->print(val_min, 2);
lcd->print("-");
lcd->print(val_max, 2);

lcd->setCursor(0, 1);

if (result == -1) {
lcd->print("TOO LITTLE");
}
else if (result == 1) {
lcd->print("TOO MUCH ");
}
else {
lcd->print("PASSED ");
}
}

void LCD::clear_row(int row) const {
lcd->setCursor(0, row);
for (int i = 0; i < columns; i++) {
lcd->print(" ");
}
lcd->setCursor(0, row);
}

void LCD::clear() const {
lcd->clear();
}

+ 27
- 0
src/lcd.h Parādīt failu

@@ -0,0 +1,27 @@
#ifndef LCD_H
#define LCD_H

#include <Arduino.h>
#include <LiquidCrystal_I2C.h>

class LCD {
private:
LiquidCrystal_I2C* lcd = nullptr; // set the LCD address to 0x27 for a 16 chars and 2 line display
const int columns = 18;
const int rows = 2;

public:
LCD();
~LCD();
void init();
void print_init_message(int calibration_weight) const;
void print_calibration(int calib_weight) const;
void print_weight(double weight, int precision, const char* unit) const;
void print_weights(double grams, double grains) const;
void print_control_result(String name, double val_min, double val_max, int result);
void clear_row(int row) const;
void clear() const;
};

#endif

+ 92
- 0
src/main.cpp Parādīt failu

@@ -0,0 +1,92 @@
#include <Arduino.h>
#include <EEPROMex.h>

#include "lcd.h"
#include "serial.h"
#include "scale.h"
#include "buttons.h"
#include "weight_controller.h"

#define shift_element 3

// =====================
// ======= SETUP =======
// =====================
LCD lcd;
SerialIO serial;
Scale scale;
Buttons buttons;
WeightControllerPool pool;

void setup()
{
//
// INIT
//
lcd.init();
serial.init();
scale.init();
buttons.init();
pool.init();

//
// DISPLAY INIT MESSAGES
//
serial.print_init_message();
lcd.print_init_message(scale.get_calibration_weight());
lcd.clear();
//
// DISPLAY INIT MESSAGES
//
}

void loop()
{
//
// ON BUTTON PRESSED ACTION
//
if (buttons.is_any_pressed())
{
buttons.on_button_pressed(scale, pool, lcd);
}

//
// READ WEIGHT
//
scale.read();

if (pool.is_controller_displayed()) {
//
// SHOW CONTROL RESULT
//
WeightController &controller = pool.get();
int result = controller.compare(scale.get_average_grain());
lcd.print_control_result(controller.get_name(), controller.get_val_min(), controller.get_val_max(), result);
//
// SHOW CONTROL RESULT
//
} else {
//
// PRINT WEIGHT
//
lcd.print_weights(scale.get_average_gram(), scale.get_average_grain());
//
// PRINT WEIGHT
//
}

//
// PROCESS REQUESTS FROM SERIAL
//
if (serial.is_available())
{
serial.on_command(scale, pool, lcd);
if (serial.is_debug_info_allowed())
{
serial.print_debug_info(scale.get_raw(), scale.get_average_raw(), scale.get_offset(), scale.get_weight(), scale.get_actual_gram(), scale.get_average_gram(), scale.get_average_grain());
}
}
//
// PROCESS REQUESTS FROM SERIAL
//
}

+ 43
- 0
src/scale.cpp Parādīt failu

@@ -0,0 +1,43 @@
#include "scale.h"

void Scale::init() {
scaled_weight = EEPROM.readDouble(e_scale);
int gain = EEPROM.readInt(e_gain);

hx711.begin(out, clck, gain);
offset = init_reading();
}

long Scale::init_reading() {
hx711.read_average(20);
return hx711.read_average(NUMBER_OF_READINGS);
}

void Scale::read() {
raw = hx711.read();
actual_gram = (raw - offset) / scaled_weight;

if (abs(actual_gram - average_gram) > EPSILON) {
sum = 0;
count = 0;
sum_raw = 0;
average_raw = raw;
average_gram = actual_gram;
}
else {
sum += actual_gram;
sum_raw += raw;
count++;
average_gram = sum / count;
average_raw = sum_raw / count;
}
}

void Scale::tare() {
offset = average_raw;
}

void Scale::calibrate() {
scaled_weight = (raw - offset) / get_calibration_weight();
EEPROM.updateDouble(e_scale, scaled_weight);
}

+ 80
- 0
src/scale.h Parādīt failu

@@ -0,0 +1,80 @@
#ifndef SCALE_H
#define SCALE_H

#include <HX711.h>
#include <EEPROMex.h>

#define e_scale 0
#define e_calib_w 8
#define e_gain 10

#define none 0
#define tar 1
#define cal 2
#define shift_element 3

#define delay_vypis 800

#define NUMBER_OF_READINGS 30

class Scale {
private:
HX711 hx711;

double sum = 0;
long sum_raw = 0;
int count = 0;
double average_gram = 0;
long average_raw = 0;
double EPSILON = 0.01;

long raw;

long offset = 0;
double scaled_weight = 15940.0; // aprox. 15 g
double actual_gram;

const int out = 2;
const int clck = 3;

public:
void init();
long init_reading();
void read();
void tare();
void calibrate();

long get_raw() const {
return raw;
}
long get_average_raw() const {
return average_raw;
}
long get_offset() const {
return offset;
}

int get_calibration_weight() const {
return EEPROM.readInt(e_calib_w);
}

double get_weight() const {
return scaled_weight;
}

double get_actual_gram() const {
return actual_gram;
}

double get_average_grain() const {
return average_gram / 0.06479891;
}

double get_average_gram() const {
return average_gram;
}
};

#endif

+ 119
- 0
src/serial.cpp Parādīt failu

@@ -0,0 +1,119 @@
#include "serial.h"
#include "lcd.h"

void SerialIO::init() {
Serial.begin(9600);
}

bool SerialIO::is_available() const {
return Serial.available();
}

void SerialIO::print_gain(int gain) const {
Serial.print(F("zosilnenie = "));
Serial.print(gain, DEC);
Serial.println();
}

bool SerialIO::is_debug_info_allowed() const {
return this->debug_info_allowed;
}

void SerialIO::print_init_message() const {
Serial.println(F(" milivahy"));
Serial.println(F(" "));
Serial.println(F(" v - vypis hodnot zap-vyp"));
Serial.println(F(" r - presnost zobrazenia [r 3 2]"));
Serial.println(F(" t - tare - nulovanie"));
Serial.println(F(" c - kalibracia"));
Serial.println(F(" g - zosilnenie 64, 128 [g 128]"));
Serial.println(F(" w - kalibracne zavazie v g [ w 1]"));
Serial.println(F(" p - nastavenie porovnania [ p 1 IT_1 2.0 3.0]"));
Serial.println();
}

void SerialIO::on_command(Scale& scale, WeightControllerPool& pool, LCD& lcd)
{
char var = Serial.read();
switch (var)
{
case 'c':
scale.calibrate();
lcd.print_calibration(scale.get_calibration_weight());
Serial.println();
Serial.print(F("Scale = "));
Serial.println(scale.get_weight());
break;
case 't':
scale.tare();
break;
case 'v':
debug_info_allowed = !debug_info_allowed;
break;
case 'w':
int calib_weight = Serial.parseInt();
Serial.print(F("calibration weight = "));
Serial.print(calib_weight, DEC);
Serial.println(F(" g"));
EEPROM.writeInt(e_calib_w, calib_weight);
break;
case 'r':
des_m_g = Serial.parseInt();
des_m_grain = Serial.parseInt();
break;
case 'p': {
int index = Serial.parseInt();
String name = Serial.readStringUntil(' ');
double val_min = Serial.parseFloat();
double val_max = Serial.parseFloat();

for (int j = 0; j < pool.get_max(); j++)
{
WeightController& controller = pool.get(j);
Serial.println();
Serial.print(controller.get_name());
Serial.print(F(" "));
Serial.print(controller.get_val_min(), 2);
Serial.print(F(" "));
Serial.print(controller.get_val_max(), 2);
}
break;
} case 'g':
int gain = Serial.parseInt();
if (gain == 64 || gain == 128)
{
EEPROM.writeInt(e_gain, gain);
}
print_gain(gain);
break;
case 'h':
print_init_message();
break;
}
}

void SerialIO::print_debug_info(long raw, double average_raw, long offset, double weight, double gram, double average_gram, double grain) const {
Serial.print(F("RAW = "));
Serial.print(raw);

Serial.print(F(", AV_RAW = "));
Serial.print(average_raw);

Serial.print(F(", offset = "));
Serial.print(offset);

Serial.print(F(", RAW-offset = "));
Serial.print(raw - offset);

Serial.print(F(", Scale = "));
Serial.print(weight);

Serial.print(F(", gram = "));
Serial.print(gram, des_m_g);

Serial.print(F(", average = "));
Serial.print(average_gram, des_m_g);

Serial.print(F(", grain = "));
Serial.println(grain, des_m_grain);
}

+ 29
- 0
src/serial.h Parādīt failu

@@ -0,0 +1,29 @@
#ifndef SERIAL_H
#define SERIAL_H

#include <Arduino.h>
#include "weight_controller.h"
#include "scale.h"
#include "lcd.h"

#define e_calib_w 8
#define e_gain 10

class SerialIO {
private:
int des_m_g = 5;
int des_m_grain = 3;

bool debug_info_allowed = false;

public:
void init();
bool is_available() const;
void print_gain(int gain) const;
bool is_debug_info_allowed() const;
void print_init_message() const;
void on_command(Scale& scale, WeightControllerPool &pool, LCD &lcd);
void print_debug_info(long raw, double average_raw, long offset, double weight, double gram, double average_gram, double grain) const;
};

#endif

+ 45
- 0
src/weight_controller.cpp Parādīt failu

@@ -0,0 +1,45 @@
#include "weight_controller.h"

void WeightController::init(String name, double min, double max) {
this->name = name;
this->val_min = min;
this->val_max = max;
}

int WeightController::compare(double weight) const {
if (val_min > weight) {
return -1;
}
else if (val_max < weight) {
return 1;
}
return 0;
}


void WeightControllerPool::next() {
if (current == 0) {
controller_displayed = true;
}

current++;
if (current - 1 >= max) {
controller_displayed = false;
current = 0;
}
}

WeightController& WeightControllerPool::get() {
return items[current - 1];
}

WeightController& WeightControllerPool::get(int index) {
if (index < 0) {
return items[0];
}
else if (index > max) {
return items[max];
}

return items[index];
}

+ 77
- 0
src/weight_controller.h Parādīt failu

@@ -0,0 +1,77 @@
#ifndef WEIGHT_CONTROLLER_H
#define WEIGHT_CONTROLLER_H

#include <Arduino.h>

class WeightController {
private:
String name;
double val_min;
double val_max;

public:
void init(String name, double min, double max);
int compare(double weight) const;

String get_name() const {
return name;
}

double get_val_min() const {
return val_min;
}

double get_val_max() const {
return val_max;
}

void set_name(String name) {
this->name = name;
}

void set_min(double min) {
this->val_min = min;
}

void set_max(double max) {
this->val_max = max;
}
};

class WeightControllerPool {
private:
int max = 4;
WeightController items[4];

int current = 0;
bool controller_displayed = false;

public:
void init() {
items[0].init("9mm", 190, 200);
items[1].init(".223", 0, 1);
items[2].init("6.5", 200, 300);
items[3].init(".308", 2, 3);
}

void set_item(int index, String name, double min, double max) {
WeightController &controller = items[index];
controller.set_name(name);
controller.set_min(min);
controller.set_max(max);
}

bool is_controller_displayed() const {
return controller_displayed;
}

int get_max() const{
return max;
}

void next();
WeightController &get();
WeightController &get(int index);
};

#endif

+ 11
- 0
test/README Parādīt failu

@@ -0,0 +1,11 @@

This directory is intended for PlatformIO Unit Testing and project tests.

Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.

More information about PlatformIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html

Notiek ielāde…
Atcelt
Saglabāt