-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat ph #1
base: main
Are you sure you want to change the base?
Feat ph #1
Changes from all commits
554e6e1
c21f4d5
be80fdd
27e3c4f
e5423cb
2cc9aad
2645fa9
3efc6c2
958c3fa
1d7c435
47db389
bb29269
96cccbe
ad8d3c1
e21475e
fd1a8e1
aeeb3ad
e3c27c9
5b1ef10
b171787
ae5084c
2849f71
de24d48
f2fc42d
06982e5
dcee547
7d9dd9e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Language: Cpp | ||
BasedOnStyle: WebKit | ||
BreakBeforeBraces: Attach | ||
NamespaceIndentation: None |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# TroykaPH API | ||
|
||
## `class TroykaPH` | ||
|
||
Create an object of type `TroykaPH` to control the [module for measuring pH of liquids TroykaPH] (https://amperka.ru/product/troyka-ph-sensor). | ||
|
||
### `TroykaPH(uint8_t pin)` | ||
|
||
Creates a new TroykaPH object. | ||
|
||
- `pin`: analog pin to which the module is connected. | ||
|
||
### `void begin(float correction = 1.0, float zeroShift = 2.0)` | ||
|
||
- `correction` - AVR's internal voltage reference offset correction. | ||
- `zeroShift` - correction of the real shift `0` during measurements. | ||
|
||
Initializes the library. Call this method before you begin interacting with TroykaPH. For example, in the `setup()`. | ||
|
||
- `correctionMultiplier`: correction factor obtained as a result of the calibration procedure. If absent, it is taken equal to `1`. | ||
|
||
### `void update(long periodMilliseconds = 1000)` | ||
|
||
Performs periodic reading of sensor and correction factors. Place his call in `loop()`. | ||
|
||
- `periodMilliseconds`: sensor polling period. | ||
|
||
### `float read() const;` | ||
|
||
Returns the last measured pH value. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# TroykaPH API (RUS) | ||
|
||
## `class TroykaPH` | ||
|
||
Создайте объект типа `TroykaPH` для управления [модулем измерения pH жидкостей TroykaPH](https://amperka.ru/product/troyka-ph-sensor). | ||
|
||
### `TroykaPH(uint8_t pin)` | ||
|
||
Создает новый объект TroykaPH. | ||
|
||
- `pin`: аналоговый пин к которому подключен модуль. | ||
|
||
### `void begin(float correction = 1.0, float zeroShift = 2.0)` | ||
|
||
- `correction` - коррекция с учетом сдвига напряжения внутреннего источника опорного напряжения AVR. | ||
- `zeroShift` - коррекция с учетом реального сдвига `0` при измерениях. | ||
|
||
Инициализирует библиотеку. Вызовите этот метод до начала взаимодействия с TroykaPH. Например в функции `setup()`. | ||
|
||
- `correctionMultiplier`: корректировочный множитель полученный в результате процедуры калибровки. При отсутствии принимается равным `1`. | ||
|
||
### `void update(long periodMilliseconds = 1000)` | ||
|
||
Производит периодическое чтение показаний датчика и корректировочных коэфициентов. Разместите его вызов в `loop()`. | ||
|
||
- `periodMilliseconds`: период опроса датчика. | ||
|
||
### `float read() const;` | ||
|
||
Возвращает последнее замеренное значение pH. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
|
||
Берем плату Arduino или совместимую, подключаем по USB, прошиваем этим скетчем и | ||
запускаем скетч. Выполняем указания в Serial Monitor. | ||
|
||
Важно: надо ввести в Serial Monitor значение в милливольтах - 4 цифры, незначащие | ||
правые дополнить нулями. | ||
|
||
*/ | ||
|
||
/* | ||
This example don't use library. It demonstrates TroykaPH calibration procedure | ||
*/ | ||
|
||
float measureVop() { | ||
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | ||
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | ||
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) | ||
ADMUX = _BV(MUX5) | _BV(MUX0); | ||
#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) | ||
ADMUX = _BV(MUX3) | _BV(MUX2); | ||
#else | ||
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | ||
#endif | ||
delay(75); | ||
float Vop = 0; | ||
for (uint8_t i = 0; i < 100; i++) { | ||
ADCSRA |= _BV(ADSC); | ||
while (bit_is_set(ADCSRA, ADSC)) | ||
; | ||
uint8_t low = ADCL; | ||
uint8_t high = ADCH; | ||
|
||
Vop += (float)((high << 8) | low) * 5. / 1024.; | ||
delay(10); | ||
} | ||
return Vop / 100.; | ||
} | ||
|
||
float measureZeroLevel() { | ||
(void)analogRead(A4); | ||
float Vzero = 0; | ||
for (uint8_t i = 0; i < 100; i++) { | ||
Vzero += (float)analogRead(A4) * 5. / 1024.; | ||
delay(10); | ||
} | ||
return Vzero / 100.; | ||
} | ||
|
||
float factor; | ||
|
||
void setup() { | ||
Serial.begin(9600); | ||
while (!Serial) | ||
; | ||
|
||
Serial.print("\n\n\nTroyka pH module zero-shift calibration procedure\n\n"); | ||
Serial.print("- Connect TroykaPH module to Arduino board.\n"); | ||
Serial.print("- Shortcut TroykaPH module BNC input to ground.\n"); | ||
Serial.print("- Measure (using good multimeter) Arduino board feed voltage between 5V and GND pins\n"); | ||
Serial.print("- Input this value in millivolts to Serial Monitor input line, press 'Send' after it.\n"); | ||
Serial.print("For example: if measured value is '4.93' volts - punch '4930'\n\n"); | ||
} | ||
|
||
void loop() { | ||
if (Serial.available() > 0) { | ||
float Vmeasured = (float)Serial.parseInt() / 1000; | ||
if (Vmeasured == 0) | ||
return; | ||
Serial.print("Voltage measured by multimeter (V) = "); | ||
Serial.println(Vmeasured, 3); | ||
float Vop = measureVop(); | ||
Serial.print("Voltage of internal reference (V) = "); | ||
Serial.println(Vop, 3); | ||
float VccCalculated = Vop * 5. / 1.1; | ||
Serial.print("Calculated Vcc (V) = "); | ||
Serial.println(VccCalculated, 3); | ||
|
||
factor = (float)(VccCalculated) / (float)(Vmeasured); | ||
|
||
float VccReal = 5. / factor; | ||
Serial.print("Real Vcc (V) = "); | ||
Serial.println(VccReal, 3); | ||
|
||
float Vzero = measureZeroLevel(); | ||
Serial.print("Calculated zero-shift voltage (V) = "); | ||
Serial.println(Vzero, 3); | ||
float VzeroReal = Vzero / factor; | ||
Serial.print("Real zero-shift voltage (V) = "); | ||
Serial.println(VzeroReal, 3); | ||
|
||
Serial.print("Calibration complete."); | ||
Serial.print("\n\nCall in your 'setup()' method {your-pH-sensor-name}.begin("); | ||
Serial.print(factor, 3); | ||
Serial.print(", "); | ||
Serial.print(VzeroReal, 3); | ||
Serial.print("); \n\n"); | ||
|
||
Serial.println("Recalibration is needed if you change Arduino board to another.\n\n"); | ||
delay(5000); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you use microcontroller registers? After all, the calibration example won't work with the Arduino Due and ESP8226 boards? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the standard Arduino API, there is no way to read the voltage at the internal Vref. There is only a way to use it instead of Aref. Now, as you can see, there is a way only for different AVRs. The options for other controllers can be worked on in the next version. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I propose to write from which boards support the calibration process. And there are no other options easier than using Vref? |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,32 @@ | ||||||||
/* | ||||||||
This example demonstrate pH value reading | ||||||||
*/ | ||||||||
#include "Arduino.h" | ||||||||
|
||||||||
// Include library | ||||||||
#include "TroykaPH.h" | ||||||||
|
||||||||
TroykaPH phMeter(A4); // set used analog pin | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest using pin A0, it is used everywhere by default. |
||||||||
|
||||||||
uint32_t lastShowingTime; | ||||||||
constexpr uint32_t INTERVAL = 3000; | ||||||||
|
||||||||
void setup() { | ||||||||
phMeter.begin(); // if module not calibrated or... | ||||||||
// phMeter.begin(correction,zeroShift); // if you have it (use calibrate.ino) for it | ||||||||
|
||||||||
Serial.begin(9600); | ||||||||
lastShowingTime = millis(); // show result once per 3 seconds | ||||||||
} | ||||||||
|
||||||||
void loop() { | ||||||||
uint32_t currentTime = millis(); | ||||||||
phMeter.update(1000); // real read from sensor once per second | ||||||||
// (you can increase this period, in practice pH value changing too slowly) | ||||||||
|
||||||||
if (currentTime - lastShowingTime > INTERVAL) { | ||||||||
lastShowingTime = currentTime; | ||||||||
Serial.print("\nCurrent pH: "); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For Arduino users, it is better to do a newline at the end of the output: |
||||||||
Serial.print(phMeter.read(), 1); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two decimal places is normal for solutions of PH. |
||||||||
} | ||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
####################################### | ||
# Syntax Coloring Map TroykaPH | ||
####################################### | ||
|
||
####################################### | ||
# Datatypes (KEYWORD1) | ||
####################################### | ||
|
||
TroykaPH KEYWORD1 | ||
|
||
####################################### | ||
# Methods and Functions (KEYWORD2) | ||
####################################### | ||
|
||
begin KEYWORD2 | ||
update KEYWORD2 | ||
read KEYWORD2 | ||
|
||
####################################### | ||
# Constants (LITERAL1) | ||
####################################### |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
name=TroykaPH | ||
version=1.0.0 | ||
author=Yury Botov <[email protected]> | ||
maintainer=Amperka <amperka.ru> | ||
sentence=Library for TroykaPH sensor. | ||
paragraph=Allows calibrate and read sensor value | ||
category=Sensor | ||
url=https://github.com/amperka/TroykaPH | ||
architectures=* |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,89 @@ | ||||||
/* | ||||||
* This file is a part of TroykaPH library. | ||||||
* | ||||||
* Product page: https://amperka.ru/product/troyka-ph-sensor | ||||||
* © Amperka LLC (https://amperka.com, [email protected]) | ||||||
* | ||||||
* Author: Yury Botov <[email protected]> | ||||||
* License: GPLv3, all text here must be included in any redistribution. | ||||||
*/ | ||||||
|
||||||
#include "TroykaPH.h" | ||||||
|
||||||
TroykaPH::TroykaPH(uint8_t pin) { | ||||||
_pin = pin; | ||||||
_lastValue = 7; | ||||||
_correction = 1.0; | ||||||
_nextMeasureTime = 0; | ||||||
} | ||||||
|
||||||
void TroykaPH::begin(float correction, float zeroLevel) { | ||||||
_correction = correction; | ||||||
_zeroLevel = zeroLevel; | ||||||
} | ||||||
|
||||||
static float fmap(float value, float minVal, float maxVal, float minOut, float maxOut) { | ||||||
return (value - minVal) / (maxVal - minVal) * (maxOut - minOut) + minOut; | ||||||
} | ||||||
|
||||||
void TroykaPH::update(long periodMilliseconds) { | ||||||
constexpr float idealVcc = 5.0; | ||||||
constexpr float minPh = 0.0; | ||||||
constexpr float maxPh = 14.0; | ||||||
constexpr float phHalfRangeInVolts = 0.82; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest putting all the constants into a file |
||||||
|
||||||
float value = 0; | ||||||
if (millis() - _nextMeasureTime > periodMilliseconds) { | ||||||
_nextMeasureTime += periodMilliseconds; | ||||||
// read value | ||||||
(void)analogRead(_pin); | ||||||
delay(75); | ||||||
for (uint8_t i = 0; i < 10; i++) { | ||||||
value += (float)analogRead(_pin) * 5.0 / 1024.; | ||||||
} | ||||||
value = value / 10; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reduce the expression? |
||||||
// read real Vcc value | ||||||
float realVcc = (float)(_readVcc()) / 1000.; | ||||||
|
||||||
float result = value * idealVcc / realVcc; | ||||||
result /= _correction; // internal reference source correction | ||||||
|
||||||
_lastValue = fmap(result, _zeroLevel - phHalfRangeInVolts, _zeroLevel + phHalfRangeInVolts, minPh, maxPh); | ||||||
} | ||||||
} | ||||||
|
||||||
float TroykaPH::read() const { return _lastValue; } | ||||||
|
||||||
long TroykaPH::_readVcc() { | ||||||
constexpr float adcResolution = 1024.; | ||||||
constexpr float meanReferenceVoltage = 1.1; | ||||||
constexpr long toMillivolts = 1000L; | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, I suggest putting all the constants into a file |
||||||
long result = 0; | ||||||
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | ||||||
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | ||||||
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) | ||||||
ADMUX = _BV(MUX5) | _BV(MUX0); | ||||||
#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) | ||||||
ADMUX = _BV(MUX3) | _BV(MUX2); | ||||||
#else | ||||||
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | ||||||
#endif | ||||||
|
||||||
delay(75); | ||||||
// internal reference reading | ||||||
for (uint8_t i = 0; i < 10; i++) { | ||||||
ADCSRA |= _BV(ADSC); | ||||||
while (bit_is_set(ADCSRA, ADSC)) | ||||||
; | ||||||
|
||||||
uint8_t low = ADCL; | ||||||
uint8_t high = ADCH; | ||||||
|
||||||
result += (high << 8) | low; | ||||||
} | ||||||
result /= 10; | ||||||
|
||||||
result = (long)(adcResolution * meanReferenceVoltage) * toMillivolts / result; | ||||||
return result; | ||||||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,34 @@ | ||||||
/* | ||||||
* This file is a part of TroykaPH library. | ||||||
* | ||||||
* Product page: https://amperka.ru/product/zelo-folow-line-sensor | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
* © Amperka LLC (https://amperka.com, [email protected]) | ||||||
* | ||||||
* Author: Yury Botov <[email protected]> | ||||||
* License: GPLv3, all text here must be included in any redistribution. | ||||||
*/ | ||||||
|
||||||
#ifndef __TROYKA_PH_H__ | ||||||
#define __TROYKA_PH_H__ | ||||||
|
||||||
#include "Arduino.h" | ||||||
|
||||||
class TroykaPH { | ||||||
public: | ||||||
TroykaPH(uint8_t pin); | ||||||
void begin(float correction = 1.0, float zeroLevel = 2.0); | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is there an empty line between functions? |
||||||
void update(long periodMilliseconds = 1000); | ||||||
|
||||||
float read() const; | ||||||
|
||||||
private: | ||||||
uint8_t _pin; | ||||||
float _lastValue; | ||||||
float _correction; | ||||||
float _zeroLevel; | ||||||
uint32_t _nextMeasureTime; | ||||||
long _readVcc(); | ||||||
}; | ||||||
|
||||||
#endif //__TROYKA_PH_H__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest using only one language in comments.