ARDUINO Регулировка десятых долей

RiveR

✩✩✩✩✩✩✩
17 Мар 2020
13
1
Здравствуйте, коллеги ардуинщики, помогите начинающему с проблемой.

Дело такое делаю что то вроде термостата и требуется регулировать температуру в пределах десятых долей. Регулирую потенциометром. Что вы можете посоветовать?

#include <LiquidCrystal.h>

#include <EEPROM.h>

LiquidCrystal lcd(8, 9, 10, 11, 12, 13);

long potenciometr;
float stemp1;
float stemp2;
float stemp3;
float stemp4;
float rtemp1;
float rtemp2;
float rtemp3;
float rtemp4;
void load() {
stemp1 = EEPROM.read(1);
stemp2 = EEPROM.read(2);
stemp3 = EEPROM.read(3);
stemp4 = EEPROM.read(4);
}

void ranc_menu() {
potenciometr = analogRead(A1);
potenciometr = (map(potenciometr,0,1023,1,4));
}

void temp() {
lcd.setCursor(4, 0);
lcd.print(stemp1);
lcd.setCursor(4, 1);
lcd.print(stemp2);
lcd.setCursor(4, 2);
lcd.print(stemp3);
lcd.setCursor(4, 3);
lcd.print(stemp4);
delay(70);
}

void menu() {
if (potenciometr == 1) {
lcd.setCursor(0, 0);
lcd.print(">");
stemp1 = map(analogRead(A2),0,1023,0,100);
stemp1 = (map(stemp1,0,100,35,50));
EEPROM.write(1, stemp1);

}
if (potenciometr == 2) {
lcd.setCursor(0, 1);
lcd.print(">");
stemp2 = map(analogRead(A2),0,1023,0,100);
stemp2 = (map(stemp2,0,100,35,50));
EEPROM.write(2, stemp2);

}
if (potenciometr == 3) {
lcd.setCursor(0, 2);
lcd.print(">");
stemp3 = map(analogRead(A2),0,1023,0,100);
stemp3 = (map(stemp3,0,100,35,50));
EEPROM.write(3, stemp3);

}
if (potenciometr == 4) {
stemp4 = map(analogRead(A2),0,1023,0,100);
lcd.setCursor(0, 3);
lcd.print(">");
stemp4 = (map(stemp4,0,100,35,50));
EEPROM.write(4, stemp4);

}
if (stemp1 > 40) {
analogWrite(A3,130);

} else {
analogWrite(A3,0);

}
if (stemp2 > 40) {
analogWrite(A4,130);

} else {
analogWrite(A4,0);

}
}

void clear() {
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print(" ");
}

void word2() {
lcd.setCursor(1, 0);
lcd.print("I1");
lcd.setCursor(1, 1);
lcd.print("I2");
lcd.setCursor(1, 2);
lcd.print("I3");
lcd.setCursor(1, 3);
lcd.print("I4");
}

void word22() {
lcd.setCursor(10, 0);
lcd.print(rtemp1);
lcd.setCursor(10, 1);
lcd.print(rtemp2);
lcd.setCursor(10, 2);
lcd.print(rtemp3);
lcd.setCursor(10, 3);
lcd.print(rtemp4);
}

void setup()
{
lcd.begin(16,4);

potenciometr = 0;

stemp1 = 35;

stemp2 = 35;

stemp3 = 35;

stemp4 = 35;

rtemp1 = 40;

rtemp2 = 40;

rtemp3 = 40;

rtemp4 = 40;

load();

pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);
}


void loop()
{
ranc_menu();
word2();
word22();
menu();
temp();
clear();

}
void menu() {
if (potenciometr == 1) {
lcd.setCursor(0, 0);
lcd.print(">");
stemp1 = map(analogRead(A2),0,1023,0,400);
EEPROM.put(5, stemp1);

}

void temp() {
lcd.setCursor(4, 0);
lcd.print(float(stemp1*0.1));
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,159
1,267
Москва
Посоветую использовать целочисленные переменные
123 это 12.3
345 это 34.5
1-ая цифра -внутренне хранение, вторая - представление на экране
 
  • Лойс +1
Реакции: RiveR

kostyamat

★★★★★★✩
29 Окт 2019
1,097
630
@RiveR, во первых - float в Ардуино - это очень тяжёлый случай, она их очень медленно обрабатывает.

Во вторых - вы пишете "мне надо регулировать", а потом мапите к четырем значениям, то есть у вас потенциометр работает как переключатель четырех положений. Потрудитесь объяснить сие недоразумение.

В третьих - (исли таки вы решите работать с float, что сильно излишне) записать его в один байт, а вы именно так и пишете - не удается. Float в этом микроконтроллере имеет размер 4-ре байта.

В четвёртых - EEPROM.read и EEPROM.write пишут только один байт, для того, чтобы записать больше (float 4 байта) нужно использовать EEPROM.get и EEPROM.put

В пятых - указывая адрес записи, нужно учитывать размер записываемых данных, указывать адрес 1,2,3 нельзя, вы будете писать поверх уже записанных данных, нужно чередование с учётом размера
EEPROM.put(1, data) а следующий адрес равен предыдущий+4
EEPROM.put(5, data) и т.д.

В шестых - у вас основная ошибка в том, что вы сразу хотите во флоат, а по факту:
у вас analogRead() возвращает значения 0 - 1023, это беззнаковое 2-байтовое число, которыми ардуино оперирует очень быстро, к тому же в ЕЕПРОМ так же помещается всего в две ячейки.
Не проще ли оперировать в самой программе именно этими числами, а к float приводить только для вывода на экран?

long potenciometr; //так переменная занимает 4-ре байта, это избыточно, да и принимать минусовые значения она не должна. Учитесь не разбазаривать оперативную память, ее очень мало, всего лишь 2048 байт.
float stemp1;

.....
stemp1 = EEPROM.read(1);

заменить на

uint16_t potenciometr; // так та же переменная занимает всего 2 байта, этого для 0-1023 достаточно
uint16_t stemp1; // зачем все эти преобразование во флоат? Программе это не надо, это надо нам, чтобы выдеть на экране, вот и приводите // к флоат только перед выводом на экран, а не в начале программы.

.........

EEPROM.get(1, stemp1); // так мы сможем одной командой прочитать данные любого размера
EEPROM.put(1, stemp1); // а так записать

......

EEPROM.get(3, stemp2); // а так прочитаем следующее значение, обратите внимание на адрес, он 3, а не 2. Потому как uint16_t stemp1 занимает 2 байта. Вам бы вообще, о типах и размерах данных в ардуино, почитать стоит. Это вообще то, с чего начинать нужно.

В седьмых -
stemp1 = map(analogRead(A2),0,1023,0,100);
stemp1 = (map(stemp1,0,100,35,50));


Что это? Зачем это?
Если вы таким образом хотели получить значение float типа 23.5, то я сильно сомневаюсь, что у вас это получилось. Так как map() не умеет возвращать вещественное число, а только целые числа.
Если вам таки хочется получить float, вам нужно вычислить коефициент, и умножать на него значение analogRead().
При этом нужно понимать, что если целое число, которое выдает analogRead() умножить на дробный коэффициент, на выходе все равно получите целое число, без знаков после запятой. Поэтому нужно использовать приведение к типу (float)
типа так

uint16_t Var;
float VarF;

Var = analogRead();
VarF = (float)Var * ваш_коэффициент;

как рассчитать коэффициент? Это уже совершенно другой вопрос, там может быть достаточно сложная формула, которая зависит от того, на сколько ваш датчик/потенциометр линеен, или что вы там во float переводите.
 
Изменено:

RiveR

✩✩✩✩✩✩✩
17 Мар 2020
13
1
@kostyamat, не правильно описал проблему, моя ошибка, есть два потенциометра, одним я выбираю переменную stemp которую нужно изменить и вторым уже меняю значение stemp.

rtemp это на будущее будет выводится температура с датчика( сейчас прописал руками что бы посмотреть как оно будет на дисплее)

map использовал что бы получить диапазон от 35 до 50 градусовIMG_20200317_141051_6.jpg
 

kostyamat

★★★★★★✩
29 Окт 2019
1,097
630
есть два потенциометра, одним я выбираю переменную stemp которую нужно изменить и вторым уже меняю значение stemp.
Ну ок. Имеет право на жизнь. Только при чем здесь переменные типа флоат?
Вот смотрите, вы пишете
lcd.setCursor(4, 0);
lcd.print(stemp1);

Это можно заменить на

lcd.setCursor(4, 0);
lcd.print((float)Var * ваш_коэфициент);

map использовал что бы получить диапазон от 35 до 50 градусов
И что, получили? map() не возвращает float, а int. А как же "регулировка десятых долей"?
 
  • Лойс +1
Реакции: RiveR

PiratFox

★★★★★✩✩
13 Фев 2020
1,695
472
@kostyamat, боже ж мой, люди создают проблемы на пустом месте. Для начала применить энкодер, да и всего делов. И потом, можно масштабировать данные термодатчика, и не использовать переменные типа float.
 
Изменено:

RiveR

✩✩✩✩✩✩✩
17 Мар 2020
13
1
@kostyamat, спасибо вам огромное за такие ёмкие и полные ответы и подсказки, все получилось!!)
 
Изменено:
  • Лойс +1
Реакции: kostyamat