Необходимо привести скетч в порядок.
- Войдите на сайт для отправки комментариев
Сб, 20/07/2019 - 09:19
Программа написана и в принципе работает. Но есть неприятные траблы - нечеткое срабатывание энкодеров. Схема "железа" исправна: в "чистом виде" (просто считывание энкодеров) проходит нормально. Понимаю, что в полном скетче имеется какой-то конфликт. По причине слабой подготовки выудить проблему не смог. Необходимо привести программу в порядок. Лучше общение в почту: bma280156@mail.ru (возможно ли, стоимость, сроки...)
Программа (прошу не пинать, слаб я еще в программировании ардуино):
//АРДУИНО УНО Управление клапаном отбора
//________Подключение библиотеки термометров
#include <OneWire.h>
//________Объявление пинов температурных датчиков
OneWire ds_col(9); // Датчик колонны на нпине 9
OneWire ds_add(8); // Дополнительный датчик на пине 8
//________Подвязывание переменных к библиотеке датчиков
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr_col[8];
byte addr_add[8];
long reading_time;
#include "LedControl.h" //Библиотека индикаторов
/* Рацветка шлейфов на индикацию:
GND - фиолетовый
Din (dout) - пин 11 - желтый
CS (load) - пин 12 - зеленый
CLK - пин 13 - синий
четвертая цифра "X" - количество модулей */
LedControl lc = LedControl(10, 12, 11, 4); //создаём объект класса LedControl (din,clk,cs,X)
//ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
// Массив с закодированными символами для надписей.
byte bukvy[37] =
{
B01110111, //A-0
B01111111, //B-1
B01001110, //C-2
B01001111, //E-3
B01000111, //F-4
B01011110, //G-5
B00110111, //H-6
B00111000, //J-7
B00001110, //L-8
B01111110, //O-9
B01100111, //P-10
B01011011, //S-11
B00111110, //U-12
B00111011, //Y-13
B01101101, //Z-14
B01011111, //Б-15
B01000110, //Г-16
B01111001, //З-17
B01110110, //П-18
B00110011, //Ч-19
B00011111, //Ь-20
B00011111, //b-21
B00001101, //c-22
B00111101, //d-23
B00010111, //h-24
B00010000, //i-25
B00011000, //j-26
B00001100, //l-27
B00010101, //n-28
B00011101, //o-29
B00011100, //u-30
B00000101, //г-31
B01100011, //°-32
B00001000, //_-33
B00000001, //--34
B00001001, //:-36
B00000000, //пусто-37
};
//Переменные кнопок
volatile int but_delta_val=0; //Значения кнопки дельты
volatile int but_valve_val=0; //Значения кнопки клапана
// Переменные значения и времени считывания энкодера дельты
unsigned char enc_delta_a; //Значение вывода А энкодера дельты
unsigned char enc_delta_b; //Значение вывода В энкодера дельты
unsigned char enc_delta_a_prev=0; //Предыдущее значение вывода А энкодера дельты
unsigned long enc_delta_curr_time; //Текущая временная переменная энкодера дельты
unsigned long enc_delta_loop_time; //Предыдущая временная переменная энкодера дельты
int enc_delta_val; //Значение энкодера дельты
// Переменные значения и времени считывания энкодера клапана
unsigned char enc_valve_a; //Значение вывода А энкодера клапана
unsigned char enc_valve_b; //Значение вывода В энкодера клапана
unsigned char enc_valve_a_prev=0; //Предыдущее значение вывода А энкодера клапана
unsigned long enc_valve_curr_time; //Текущая временная переменная энкодера клапана
unsigned long enc_valve_loop_time; //Предыдущая временная переменная энкодера клапана
int enc_valve_val; //Значение энкодера клапана
//Переменные температуры
volatile int temperature_colonna=0; //Температура колонны
volatile int temperature_addition=0; //Температура дополнительного датчика
volatile int temperature_delta=0; //Температура отсечки
unsigned long temperature_time; //Переменная задержки времени для считывания датчиков температуры
unsigned long temperature_loop_time; //Переменная задержки времени для считывания датчиков температуры предыдущая
//Переменные клапана
int valve_n=0; //Количество опросов клапана
unsigned long valve_time=0; //Текущая временная переменная работы клапана
unsigned long valve_time_prev=0; //Предыдущая временная переменная работы клапана
volatile int valve; //Скважность клапана с шагом 1/100 от 0 до 1.00
volatile int valve_on; //Время открытого клапана (мсек)
volatile int valve_off; //Время закрытого клапана (мсек)
volatile int encoder_valve_position; //Статус энкодера клапана
volatile int encoder_valve_position_new; //Значение энкодера клапана
// Переменные для индикации
volatile int tys; //Тысячи
volatile int sot; //Сотни
volatile int des; //Десятки
volatile int edi; //Единицы
void setup()
{
Serial.begin(115200);
//Назначаем пины
for (int pin=2; pin<10;pin++) //На вход
{
pinMode(pin, INPUT);
}
for (int pin=10; pin<14;pin++) //На выход
{
pinMode(pin, OUTPUT);
}
//Инициализация модуля индикаторов
for (int ind=0;ind<4;ind++)
{
lc.shutdown(ind, false); //Выводим из спящего режима
lc.setIntensity(ind,3); //Яркость дисплеев на 3. Всего возможных режимов яркости от 0 до 15
lc.clearDisplay(ind); //Очистить дисплей
}
//Прописываем "Col °" (температура колонны)
lc.setRow(0, 7, bukvy[2]);//Индикация C"
lc.setRow(0, 6, bukvy[29]);//Индикация "o"
lc.setRow(0, 5, bukvy[27]);//Индикация "l"
lc.setRow(0, 0, bukvy[32]);//Индикация "°"
lc.setDigit(0, 3, 0, false);
lc.setDigit(0, 2, 0, true);
lc.setDigit(0, 1, 0, false);
//Прописываем "Add °" (второй датчик температуры)
lc.setRow(3, 7, bukvy[0]);//Индикация "A"
lc.setRow(3, 6, bukvy[23]);//Индикация "d"
lc.setRow(3, 5, bukvy[23]);//Индикация "d"
lc.setRow(3, 0, bukvy[32]);//Индикация "°"
lc.setDigit(3, 3, 0, false);
lc.setDigit(3, 2, 0, true);
lc.setDigit(3, 1, 0, false);
//Прописываем "Adj °" (настройка дельты)
lc.setRow(1, 7, bukvy[0]);//Индикация "A"
lc.setRow(1, 6, bukvy[23]);//Индикация "d"
lc.setRow(1, 5, bukvy[26]);//Индикация "j"
lc.setRow(1, 0, bukvy[32]);//Индикация "°"
lc.setDigit(1, 3, 0, false);
lc.setDigit(1, 2, 0, true);
lc.setDigit(1, 1, 0, false);
//Прописываем "Pro" (скважность клапана)
lc.setRow(2, 7, bukvy[10]);//Индикация "P"
lc.setRow(2, 6, bukvy[31]);//Индикация "r"
lc.setRow(2, 5, bukvy[29]);//Индикация "o"
lc.setDigit(2, 2, 0, true);
lc.setDigit(2, 1, 0, false);
lc.setDigit(2, 0, 0, false);
//Назначение прерываний
attachInterrupt(0, BUTTON_DELTA, RISING); //Прерывание дельты
attachInterrupt(1, BUTTON_VALVE, RISING); //Прерывание клапана
}
void loop()
{
//________Запрос датчикам на измерение температуры
if ( !ds_col.search(addr_col)) {}
if ( !ds_add.search(addr_add)) {}
//Инициируем датчик колонны
ds_col.reset();
ds_col.select(addr_col);
ds_col.write(0x44);
//Инициируем дополнительный датчик
ds_add.reset();
ds_add.select(addr_add);
ds_add.write(0x44);
// Опрос энкодера клапана
enc_valve_curr_time = millis();
if(enc_valve_curr_time >= (enc_valve_loop_time + 5)) // проверяем каждые 5 мсек
{
enc_valve_a = digitalRead(5); // считываем состояние выхода А энкодера
enc_valve_b = digitalRead(4); // считываем состояние выхода B энкодера
if((!enc_valve_a) && (enc_valve_a_prev))// если состояние изменилось с положительного к нулю
{
if(enc_valve_b)
{
// выход В в полож. сост., значит вращение по часовой стрелке
valve++;
if(valve>100) {valve=100;}
}
else
{
// выход В в 0 сост., значит вращение против часовой стрелки
valve--;
if(valve<0) {valve=0;}
}
}
enc_valve_a_prev = enc_valve_a; // сохраняем значение А для следующего цикла
enc_valve_loop_time = enc_valve_curr_time;
VALVE_SETUP();
}
// Опрос энкодера дельты
enc_delta_curr_time = millis();
if(enc_delta_curr_time >= (enc_delta_loop_time + 5)) // проверяем каждые 5 мсек
{
enc_delta_a = digitalRead(7); // считываем состояние выхода А энкодера
enc_delta_b = digitalRead(6); // считываем состояние выхода B энкодера
if((!enc_delta_a) && (enc_delta_a_prev))// если состояние изменилось с положительного к нулю
{
if(enc_delta_b)
{
// выход В в полож. сост., значит вращение по часовой стрелке
temperature_delta++;
if(temperature_delta>999) {temperature_delta=999;}
}
else
{
// выход В в 0 сост., значит вращение против часовой стрелки
temperature_delta--;
if(temperature_delta<0) {temperature_delta=0;}
}
}
enc_delta_a_prev = enc_delta_a; // сохраняем значение А для следующего цикла
enc_delta_loop_time = enc_delta_curr_time;
DEGREE_DELTA();
}
// Работа клапана
valve_time=millis();
if (valve_time - valve_time_prev > 100) //Опрос каждые 100 мсек
{
valve_n++;
if((valve_n<=valve)&&(temperature_colonna<temperature_delta)) {digitalWrite (13,HIGH);}
else {digitalWrite (13,LOW);}
if(valve_n==100) {valve_n=0;}
valve_time_prev=valve_time;
}
//Опрос показаний датчиков температуры 1 раз в 850 мсек
if (millis()-reading_time>850)
{
//Опрашиваем датчик колонны
present = ds_col.reset();
ds_col.select(addr_col);
ds_col.write(0xBE);
for ( i = 0; i < 9; i++) // нам необходимо 9 байт
{
data[i] = ds_col.read();
}
int16_t raw = (data[1] << 8) | data[0];
if (type_s)
{
raw = raw << 3; // разрешение 9 бит по умолчанию
if (data[7] == 0x10)
{
raw = (raw & 0xFFF0) + 12 - data[6];
}
}
else
{
byte cfg = (data[4] & 0x60);
}
temperature_colonna=raw / 1.6;
//Опрашиваем дополнительный датчик
present = ds_add.reset();
ds_add.select(addr_add);
ds_add.write(0xBE);
for ( i = 0; i < 9; i++) // нам необходимо 9 байт
{
data[i] = ds_add.read();
}
//int16_t raw = (data[1] << 8) | data[0];
raw = (data[1] << 8) | data[0];
if (type_s)
{
raw = raw << 3; // разрешение 9 бит по умолчанию
if (data[7] == 0x10)
{
raw = (raw & 0xFFF0) + 12 - data[6];
}
}
else
{
byte cfg = (data[4] & 0x60);
}
temperature_addition=raw / 1.6;
reading_time=millis();
DEGREE_COLONNA();
DEGREE_ADDITION();
}
}
void DEGREE_COLONNA() //Прописываем текущую температуру колонны
{
//Расчленение переменной температуры колонны
sot=temperature_colonna/100;
des=temperature_colonna% 100 / 10;
edi=temperature_colonna% 10;
// Индикация
lc.setDigit(0, 3, sot, false);
lc.setDigit(0, 2, des, true);
lc.setDigit(0, 1, edi, false);
}
void DEGREE_ADDITION() //Прописываем текущую температуру дополнительного датчика
{
//Расчленение переменной температуры дополнительного датчика
sot=temperature_addition/100;
des=temperature_addition% 100 / 10;
edi=temperature_addition% 10;
// Индикация
lc.setDigit(3, 3, sot, false);
lc.setDigit(3, 2, des, true);
lc.setDigit(3, 1, edi, false);
}
void DEGREE_DELTA() //Прописываем температуру отсечки
{
//Расчленение переменной температуры отсечки
sot=temperature_delta/100;
des=temperature_delta% 100 / 10;
edi=temperature_delta% 10;
// Индикация
lc.setDigit(1, 3, sot, false);
lc.setDigit(1, 2, des, true);
lc.setDigit(1, 1, edi, false);
}
void VALVE_SETUP() //Прописываем скважность клапана
{
//Расчленение переменной скважности клапана
sot=valve%1000/100;
des=valve%100/10;
edi=valve%10;
// Индикация
lc.setDigit(2, 2, sot, true);
lc.setDigit(2, 1, des, false);
lc.setDigit(2, 0, edi, false);
}
void BUTTON_DELTA () //Приравниваем температуру отсечки к температуре колонны
{
temperature_delta=temperature_colonna;
DEGREE_DELTA();
}
void BUTTON_VALVE () //Отключаем-подключаем клапан
{
}
Проблема в строках 170-171, пмсм: search достаточно медленная операция, зачем искать датчики на линии каждый проход loop - тайна сия великая есть. Да и энкодер - лучше на прерывание, пмсм; вместо прерывания кнопки или клапана, если не хотите возиться с PCINT.
Да и каждый проход loop посылать датчикам запрос на измерение (строки 173-179) - совершенно точно не надо: достаточно это сделать перед считыванием с них, один раз в секунду, например). Команда 0x44 (запустить конвертацию) - просто запустит конвертацию, и через N миллисекунд (зависит от настроенной разрядности) в регистре данных у датчика будет сконвертированная температура. Считывание с датчика - просто считывает этот регистр. Посему конвертацию запускать очень часто - смысла нет, достаточно это делать просто перед считыванием температуры с датчика.
Коллега! Ты бы не мог объяснить, собственно, сам алгоритм? Ибо плохо просматривается, что именно ты хотел сделать.
Пока я понял, что ты хочешь установить температуру прекращения отбора по датчику на (кубе/колонне/середине колонны - я не уяснил)?
И еще ты хочешь выставлять скорость отбора (ШИМ клапана), которая будет действовать до достижения "отсечки"?
Я всё правильно понял? Или ты имел ввиду отбор по схеме "старт/стоп" ?
Р е а л и з у е м о - maslachenko767@mail.ru , консультации, подбор компонентов бесплатно, гарантии имеются
наверное проще (если автор распишет полное техзадание) с нуля написать, чем разбираться в чужом коде.
Чет автор крылья опустил, и про PCINT ему говорили, и про Далласы, сломался. То ТС, такую портянку накатали, осталось ведь уже чуть чуть. А в этом разделе, самое верное мнение, постом выше. ИМХО.
Коллега! Ты бы не мог объяснить, собственно, сам алгоритм?
Смотри как это должно работать...
1 - "разгоняемся" на максимальной мощности и как только верхний датчик температуры достиг первой уставки - уменьшаем мощность до тех пор, пока температура не упадёт до второй уставки, затем прибавляем мощность опять до первой уставки и тд и тп ДО появления ровной температурной полки и иже с ним - расчётной мощности нагрева. Т.е. мощность нагрева нужно ВЫЧИСЛИТЬ !!!
2 - Далее, собственно, на расчётной мощности "отбираем" через клапан и смотрим за температурой. Как только пошла "раскачка" по температуре - заканчиваем первый отбор.
Переходим к п.1 но уже с другими уставками по температуре и вычисляем уже "новую" мощность.
Отбираем уже на вновь вычисленных мощность и ШИМ клапан-а.
Ну и так далее до конечной уставки. Их там штук 6 - 8.
Ваащпе я нипайму, на форуме, где он это "подсмотрел" уже давно валяется вполне готовый и рабочий скетч, где всё это уже написано и проверено и не один год совершенствуется... правда там скутч тышш на 8 строк, разобрацца с ним это ещё тот гемор )))
Смотри как это должно работать...
Спасибо, конечно, что поделился своими наблюдениями. ;))))
1. Наш коллега что-то свое имел ввиду, это видно из представленного кода.
2. То, что ты описал и "давно лежит" лишь один из возможных и не самый оптимальный вариант. Просто к нему привыкли. Но (к примеру) технической необходимости менять мощность вообще нет. Это используется исключительно для увеличения скорости процесса, но никто не мешает разогревать сырец на той же мощности, что и рабочая у колонны. И это только самый простой пример.
Но (к примеру) технической необходимости менять мощность вообще нет.
Это тебе так кажется. Возьми колонну и на максимуме нагрева попробуй с ней "совладать"
Запиши видео, запость сЮдой. Уотт тогда я буду задавать тебе более конкретные вопросы... а пока, ты, как и ТС мягко говоря "ниФтеме" !!!