Может причина в том, что цикл начинается из состояния 0? В состоянии 0 предполагается, что таймер 3ч уже запущен. Надо либо запускать таймер в setup(), либо начинать цикл из состояния 1.
Привет!
Внимательно просмотрел проект. Как-то сложноват он мне показался :(
Я бы не стал ждать, когда воды останется на 15 мин, а, допустим, постоянно подпитывал основной бак при снижении уровня примерно менее 50% V. Не знаю как у вас с электричеством, но пока оно есть, лучше заполнить бак доверху.
Для контроля работоспособности насоса и переполнения бака я себе закупил (поставлю по весне) реле ПОтока. Иногда называется реле ПРОтока. Такие реле бывают и для сильно загрязненной среды. Гугл/Али в помощь.
Про сложность... ну да, есть такой момент. Это я еще дисплей не прикрутил :) Шучу.
Про подкачку воды. У меня есть некоторая идея - лучше выкачать воду, а потом ее закачать, чем она будет постоянно в баке. Некоторый обмен, снижающий риск застоя. Но это теория. На практике - залив сверху, забор снизу. Так что это просто некоторое внутренее желание. Хочу, чтобы вода сначала почти вся ушла из бака, а потом залилась новая.
Перед отъездом на зиму я уже погонял водопровод в ручном режиме. Т.е. бак наполнял вручную. Трехходовой вентиль включил, насос включил, 15 минут подождал, вентиль выключил, бак накачал, насос выключил :)
И вот мой опыт показывает, что при разборе воды из дома скорость наполнения емкости скваженным насосом такова, что не нужно никаких 15-ти минутных запасов воды. Вкачивает больше, чем разбирает. Так что нижний поплавок буду ставить сантиметрах в 10-15 ото дна.
Что касается электричества - бак в котельной в цоколе, без электричества насосная станция ничего по дому не раздаст, самотек невозможен (только то, что выдавид 100 литровый гидроаккумулятор). А если я генератор включаю, то какая разница? А если лефтричества нет долго, я его полюбому включу.
Относительно реле потока (или протока). Я не хочу дожидаться, пока вода пойдет в переливную трубу. Зачем? Поплавковый выключатель (продублированный на всякий случай) вполне себе вариант. А учитывая, что насос останавливается другим поплавком, то вообще предположить, что вода перельется - ну меньше 1%. А на этот процент как раз труба перелива.
Думаю, можно еще усложнить программу и прикрутить таймер, что если насос не выключается в течении 15-ти минут (нравится мне это количество, что уж тут, но можно и 25 :) ) - выключить принудительно и дать аварийную сигнализацию.
По моим соображениям, у твоей системы всего три основных состояния.
Ну и кучка дополнительных.
Опять-таки, на мой взгляд, получается два таймера, два уровнемера.
И еще на схеме забыл вставить запуск таймера по заполнению бака.
Как-то так.
Я тоже бросился было сначала код писать, но потом докумекал, что лучше сначала общий алгоритм прописать. Псоле ряда неудачных попыток остановился на опции "Фигуры горизонтальной функциональной блок-схемы" из меню Бизнес-процессы.
Как-то так.
единственное - картинка очень маленького разрешения, практически ничего не видно, кинь если не сложно на почту bob_shmidt ну там значек собаки и это все на mail.ru
про логику, дык ты посмотри на предыдущей странице темы у нас с Andy был целый эпос начиная с этого сообщения и с блок схемами и т.д. и т.п.
причесал тему слегка.
движок форума, конечно, не совсем мне понятен. некоторые мои посты я не могу отредактировать, нет такой "кнопки" (видимо это просиходит, если не просто написать новый пост, а нажатьь "ответить")
не понимаю, как удалить отдельный пост, приходится писать "заглушки"
очень жалко, что нет механизма личных сообщений...
Это конечно, смешно, но прошло больше, чем год
Когда я сел вспоминать, что я там наваял столько времени спустя, даже учитывая мою почти параноидальную склонность комментировать очевидные вещи, я с трудом справился
Поскольку задача передо мной сейчас была сугубо практическая - таки запустить автоматику, я решил оставить в стороне всякие излишества, типа дисплея (через неделю потеряшек в менюшках, отложил), типа часов реального времени (китайский шедевр при отключении упорно выдавал 0,6в с рабочей батарейки с ожидаемым сбросом времени), записи на SD (я уже и не вспомнил, что я таки хотел записывать )
Итак, вчера я все запустил. Работает. Вместо дисплея - 7 led-ов. Но, конечно, есть ряд нареканий и поводов к улучшению.
1. Логика кода была так жестко завязана на состояние поплавков в жесткой связке с светодиодами, что попытки поменять логику "мигания" подвела меня к необходимости вообще пересмотреть сам принцип сигнализации состояний. Иначе ничего не выходит.
2. При первом включении системы по умолчанию запускается полный цикл с прокачкой скважины и т.д. Но состояние поплавков считывается уже после того, как проходит цикл анализа состояния - в результате, даже если бак полный, полный цикл стартует с риском перелива (сегодня проверю, так ли это). Но почему и где это происходит - загадка. В своем же коде не могу разобраться
Попробую вообще с чистого листа начать.
Ну и плюшки на будущее.
1. Я хотел бы все-таки прикрутить сдвиговый регистр на вход (на выход уже работает). Пока не успешно.
2. Считывать состояние вентиля (там есть концевики), убрав один таймер.
3. Есть потребность летом один раз в сутки по любому прокачивать скважину, наполняя технический пруд.
4. Заказал на Али ультрасоник, очень уж хочется знать точно, сколько воды в баке. А то я его в пенал из ЭППС запаковал (иначе конденсатом заливает пол жестко) - ну и ничего не видно.
5. Дисплей, часы и SD
На память себе код
/*
WaterSystem.cpp
Created by Angbor, January 1, 2016
Released into the public domain
*/
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <WaterSystem.h>
WaterTimer::WaterTimer(long tLength, void f(), byte withFunc, String tName, String tTipe){
timerName = tName;
timerType = tTipe;
withFunction = withFunc;
ptrOnFuniction = f;
timerLength = tLength;
timerIsOn = false;
previousMillis = 0;
}
WaterTimer::WaterTimer(long tLength, byte withFunc, String tName, String tTipe){
timerName = tName;
timerType = tTipe;
withFunction = withFunc;
timerLength = tLength;
timerIsOn = false;
previousMillis = 0;
}
void WaterTimer::timerOn(unsigned long currentMillis) {
timerOverflow = false;
previousMillis = currentMillis;
timerIsOn = true;
//Serial.print(timerName);
//Serial.println(" ON (msg from timer)");
}
void WaterTimer :: timerOff() {
timerIsOn = false;
//Serial.print(timerName);
//Serial.println(" OFF (msg from timer)");
}
bool WaterTimer :: getIsTimerOn(unsigned long currentMillis){
if ((timerIsOn) && (currentMillis - previousMillis >= timerLength))
{
if (timerType == "loop") {
if (withFunction == 1) {
ptrOnFuniction();
}
previousMillis = currentMillis;
}
if (timerType == "line"){
//Serial.println("overflow (msg from timer)");
timerOverflow = true;
timerOff();
}
return true;
}
else {
return false;
}
}
/*
WaterSystem.h
Created by Angbor, January 1, 2016
Released into the public domain
*/
#ifndef WaterSystem_h
#define WaterSystem_h
#include "Arduino.h"
class WaterTimer
{
private:
long timerLength; // длительность таймера
unsigned long previousMillis;
String timerName = "nill";
void (*ptrOnFuniction)();
byte withFunction = 0;
public:
WaterTimer(long tLength, void f(), byte withFunc, String tName, String tTipe);
WaterTimer(long tLength, byte withFunc, String tName, String tTipe);
void timerOn(unsigned long currentMillis);
void timerOff();
bool getIsTimerOn(unsigned long currentMillis);
bool timerOverflow = false;
String timerType = "loop"; // or "line"
bool timerIsOn = false; // Текущее состояние On или Off
};
#endif
#include <WaterSystem.h>
// определяем пины для переключателей
#define BOTTOM_SWITCH 2
#define MIDDLE_SWITCH 3
#define TOP_SWITCH 4
#define OVERFLOW_SWITCH 5
//=== замедления циклов ======
#define READ_PIN_DELAY 100
#define REGISTR_DELAY 150
#define BLINK_DELAY 300
//=== реле ======
#define PUMP 9
#define PUMP_ON 1
#define PUMP_OFF 0
#define THREE_WAY_VALWE 10
#define TWV_ON 1
#define TWV_OFF 0
//потом надо перевести это дело как-то в часы и минуты (соответственно таймеру). сейчас пока в милисекундах
#define DOWNTIME 10800000// 3 часа, таймер 3H время простоя, после которого обязательна прокачка.
#define TWV_DELAY 1200000// 20 мин., таймер 15M время прокачки
#define TWV_OPENING 20000// 20 сек., таймер 1M время на открытие вентиля (потом надо заменить это на чтение концевика 3W
// прототипы и укзатели функций
void blinkS();
void pinReading();
void regWork();
void (*ptrBlinkS)() = blinkS;
void (*ptrPinReading)() = pinReading;
void (*ptrRegWork)() = regWork;
// -- таймеры ---------------
#define WITH_FUNCTION 1
#define WITHOUT_FUNCTION 0
WaterTimer timerBlink(BLINK_DELAY, ptrBlinkS, WITH_FUNCTION, "BLINK_DELAY", "loop");
WaterTimer timerPinRead(READ_PIN_DELAY, ptrPinReading, WITH_FUNCTION, "READ_PIN_DELAY", "loop");
WaterTimer timerRegistrDelay(REGISTR_DELAY, ptrRegWork, WITH_FUNCTION, "REGISTR_DELAY", "loop");
WaterTimer timer3H(DOWNTIME, WITHOUT_FUNCTION, "3H", "line");
WaterTimer timer1M(TWV_OPENING, WITHOUT_FUNCTION, "1M", "line");
WaterTimer timer15M(TWV_DELAY, WITHOUT_FUNCTION, "15M", "line");
bool fPumpIsOn = false;
bool f3wIsOpen = false;
bool firstSTart = true; // отслеживание первого включения платы и изменение флага в 3-х часовом таймере
// описание состояний
#define TANK_IS_EMPTY 0
#define TANK_LESS_THAN_A_HALF 1
#define TANK_MORE_THAN_A_HALF 2
#define TANK_IS_FULL 3
#define WRONG_SENSOR_COMB 4
#define TANK_OVERFLOW 5
#define SENSORS_IS_OK 6 // заглушка для функции проверки аварии, когда в прошлом вызове была авария, а сейчас нет и еще нет сигнала от сенсоров, чтобы переписать состояние
byte fSystemState = 0;
// ====== для цикла чтения пинов
#define NUM 4
#define GET(b) digitalRead(arr[b])
const byte arr[] = {BOTTOM_SWITCH, MIDDLE_SWITCH, TOP_SWITCH, OVERFLOW_SWITCH};
// устанавливаем управление сдвиговым регистром
const int latchPin = 8;
const int clockPin = 12;
const int dataPin = 11;
uint8_t ledsBurn = 0; //переменная для передачи в регистр
// =========================
byte switchState[] = {0, 0, 0, 0}; // состояние переключателей
byte lastSwitchState[] = {0, 0, 0, 0}; // предыдущее состояние
byte blinkF[] = {1, 0, 0, 1}; /*флаги для включения blink, здесь указываем по умолчанию какие диоды будут мигать (1),
а какие гореть постоянно (0)*/
byte ledS[] = {B00000001, B00000010, B00000100, B00001000}; //значения, соответствующие включенному LED
/*================================================
=============== SETUP ==========================
================================================
*/
void setup() {
{
// Timer0 уже используется функцией millis()
// чтобы не мешать, прерывемся примерно посередине и вызываем ниже функцию "Compare A"
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
}
/*Serial.begin(9600);
while (!Serial) {
}*/
unsigned long currentMillis = millis();
timerBlink.timerOn(currentMillis);
timerPinRead.timerOn(currentMillis);
timerRegistrDelay.timerOn(currentMillis);
timer3H.timerOn(currentMillis);
timer3H.timerOff();
// настройка сдвигового регистра
pinMode(latchPin, OUTPUT);//8
pinMode(clockPin, OUTPUT);//12
pinMode(dataPin, OUTPUT);//11
// инициализация реле
pinMode(PUMP, OUTPUT);//9
pinMode(THREE_WAY_VALWE, OUTPUT);//10
for (byte i = 0; i < NUM; i++) {// 2,3,4,5
pinMode(GET(i), INPUT);
}
ledsBurn = ledsBurn ^ B10000000; // включаем диод "питание ON"
}
/*================================================
=============== FUNCTIONS =====================
================================================
*/
SIGNAL(TIMER0_COMPA_vect)
{
unsigned long currentMillis = millis();
timerBlink.getIsTimerOn(currentMillis);
timerPinRead.getIsTimerOn(currentMillis);
timerRegistrDelay.getIsTimerOn(currentMillis);
timer3H.getIsTimerOn(currentMillis);
timer1M.getIsTimerOn(currentMillis);
timer15M.getIsTimerOn(currentMillis);
}
void blinkS() { // отвечает за мигание
for (byte i = 0; i < NUM /*4*/ ; i++) {
if (blinkF[i] == 1 && switchState[i] == 1) {
ledsBurn = ledsBurn ^ ledS[i];
}
}
}
void systemStateChanging (byte inInt) {
static byte st = 0;
switch (st)
{
case 0:
if ( fSystemState == TANK_IS_EMPTY && !timer3H.timerOverflow && !firstSTart)
/*бак пустой полностью && 3ч не истек и это не первое включение платы*/
{
st = 1;
timer3H.timerOff();
pumpOnOff(PUMP_ON);
}
if ((fSystemState == TANK_IS_EMPTY && timer3H.timerOverflow) || firstSTart)
/*бак пустой полностью && 3ч истек*/
{
st = 2;
firstSTart = false;
timer3H.timerOff();
threeWayOnOff(TWV_ON);
timer1M.timerOn(millis());
}
if (caseOfEmergency ()) {
st = 4;
}
break;
//==============================================
case 1:
if (fSystemState == TANK_IS_FULL) {
/*бак полный*/
st = 0;
pumpOnOff(PUMP_OFF);
timer3H.timerOn(millis());
}
if (caseOfEmergency ()) {
st = 4;
}
break;
//==============================================
case 2:
if (timer1M.timerOverflow) {
/*таймер 1М истек*/
st = 3;
timer15M.timerOn(millis());
pumpOnOff(PUMP_ON);
}
if (caseOfEmergency ()) {
st = 4;
}
break;
//==============================================
case 3:
if (timer15M.timerOverflow) {
/*таймер 15м истек*/
st = 1;
threeWayOnOff(TWV_OFF);
}
if (caseOfEmergency ()) {
st = 4;
}
break;
//==============================================
case 4:
if (inInt == 0/*сброс*/) {
st = 0;
// просто переход в обычное состояние
}
break;
}
}
bool caseOfEmergency () {
if ((fSystemState == WRONG_SENSOR_COMB) || (fSystemState == TANK_OVERFLOW)) {
timer1M.timerOff();
timer15M.timerOff();
timer3H.timerOn(millis());
threeWayOnOff(TWV_OFF);
pumpOnOff(PUMP_OFF);
if (fSystemState == WRONG_SENSOR_COMB) {
/*неверная комбинация датчиков*/
return true;
}
if (fSystemState == TANK_OVERFLOW) {
/* перелив*/
return true;
}
}
else return false;
}
void pumpOnOff (int onOrOff) {
if ((onOrOff == 1) && !fPumpIsOn) {
digitalWrite(PUMP, PUMP_ON);
ledsBurn = ledsBurn ^ B00010000;
fPumpIsOn = true;
}
if ((onOrOff == 0) && fPumpIsOn) {
digitalWrite(PUMP, PUMP_OFF);
ledsBurn = ledsBurn ^ B00010000;
fPumpIsOn = false;
}
}
void threeWayOnOff (int onOrOff) {
if ((onOrOff == 1) && !f3wIsOpen) {
digitalWrite(THREE_WAY_VALWE, TWV_ON);
ledsBurn = ledsBurn ^ B00100000;
f3wIsOpen = true;
}
if ((onOrOff == 0) && f3wIsOpen) {
digitalWrite(THREE_WAY_VALWE, TWV_OFF);
ledsBurn = ledsBurn ^ B00100000;
f3wIsOpen = false;
}
}
void sensorsRead() {
if (checkSwitchesCombination()) {
if ((switchState[0] == 1) && (switchState[1] == 0) && (switchState[2] == 0) && (switchState[3] == 0)) {
fSystemState = TANK_IS_EMPTY;
}
else if ((switchState[0] == 0) && (switchState[1] == 0) && (switchState[2] == 0) && (switchState[3] == 0)) {
fSystemState = TANK_LESS_THAN_A_HALF;
}
else if ((switchState[0] == 0) && (switchState[1] == 1) && (switchState[2] == 0) && (switchState[3] == 0)) {
fSystemState = TANK_MORE_THAN_A_HALF;
// в этом состоянии насос не включаем
}
else if ((switchState[0] == 0) && (switchState[1] == 1) && (switchState[2] == 1) && (switchState[3] == 0)) {
fSystemState = TANK_IS_FULL;
}
}
}
void led_switching (int switchNumber) {
if (switchState[switchNumber] == HIGH) {
bitWrite(ledsBurn, switchNumber, 1);
}
else {
if (switchState[switchNumber] == LOW) {
bitWrite(ledsBurn, switchNumber, 0);
}
}
}
bool checkSwitchesCombination() {
if (switchState[3] == 1) { // если переполнение
if (fSystemState != TANK_OVERFLOW) {
fSystemState = TANK_OVERFLOW;
}
return false;
}
else if (((switchState[0] == 0) && (switchState[1] == 0) && (switchState[2] == 1) && (switchState[3] == 0)) ||
((switchState[0] == 1) && (switchState[1] == 1) && (switchState[2] == 1) && (switchState[3] == 0)) ||
((switchState[0] == 1) && (switchState[1] == 0) && (switchState[2] == 1) && (switchState[3] == 0)) ||
((switchState[0] == 1) && (switchState[1] == 1) && (switchState[2] == 0) && (switchState[3] == 0))) {
if (fSystemState != WRONG_SENSOR_COMB) {
fSystemState = WRONG_SENSOR_COMB;
}
return false;
}
else { // если все ОК
if ((fSystemState == WRONG_SENSOR_COMB) || (fSystemState == TANK_OVERFLOW)) {// если в прошлом вызове была аварийная ситуация
fSystemState = SENSORS_IS_OK;
systemStateChanging(0);// сброс
}
return true;
}
}
void regWork() {
// использует подготовленную другими функциями перменную ledsBurn
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, ledsBurn);
digitalWrite(latchPin, HIGH);
}
void pinReading() {
for (byte i = 0; i < NUM; i++) {
switchState[i] = GET(i);
if (switchState[i] != lastSwitchState[i]) {
led_switching(i);
sensorsRead();
}
lastSwitchState[i] = switchState[i];//обновляем значение последнего состояния переключателя
systemStateChanging(1);
}
}
void loop() {
}
Перелива нет, если после подачи напряжения с полным баком нчинается полный цикл, то сначала идет прокачка на улицу, потом в дом и сразу же срабатывает отключение по верхнему поплавку.
Так что пока полет нормальный, всем доволен.
Не уверен, что в ближайшее время полезу что-то там менять. И так дел куча :)
Прошу прощения что вторгаюсь в Вашу тему но хочю предложить варианты работы насоса (у меня он работает в колодце с малым дебетом воды) без ардуино стоимомтью 50 центов а дальше( заисит только от потребляеьой нагрузки) в файле насос есть две схемы одна на реле вторая на оптопарах работа схеты на реле при включении устройства если верхний датчик находится в воде (7) ток через открытый транзистор включает реле и замыкает ево же контакты так как контакты нижнего датчика (8) находятся в воде ток через контакты реле самоблокирует реле до тех пор пока вода не опустится ниже контактов нижнего уровня. Цепь разомкнется и будет ждать контакта на верхнем уровне (схема представлена для электродных датчиков (я использовал стержни от батареек так как они наименее подвержны электролизу при постоянном токе) На схеме обозначено одно реле с одной групой контактов. Для комутации высокого напряжения необходимо второе реле которе подключается паралельно первому или если применять одно то с двумя группами контактов Цена только от стоимости реле На второй схеме практически тот же принцип но с использованием оптопар Я использовал самую рпспространенную РС817 и МОС30,,,, причем МОС30.... это уже управление нагрузкой (его также можно заменить на реле или с его выводов включив симистор управлять более мошной нагрузкой). И цена ниже и габариты Транзисторы могут преминятся любые на напряжение источника питания я применял КТ315В Г также о второй схеме необжодимо увеличить сопротивление резисторов при увелечении напряжения
все до сих пор работает. Из реально актуальных вопросов к доработке только один - таймер по началу закачивания бака. И то только потому, что сделал переключение в ручной режим и вентиль, переводящий вывод насоса на поли. И этот самый вентиль в котельной :/
Окрываешь вентиль на полив, включаешь вручную насос - пошел поливать. Устал, выключил насос, забыл перекрыть вентиль. Включилась автоматика - в котельной все поплыло...
Но сейчас я занялся автоматической кормушкой для кур, это поактуальнее, позже выложу проектик.
Спустя 4 годя я дозрел-таки до переделки автоматики.
Основные задачи (на память):
1. Все временные интервалы должны быть настраиваемые а не записаны намертво.
2. Добавить обработку концевых замыкателей 3-х ходового вентиля
3. Таки дисплей
4. RTC DS3231
5. Добавить связь по nRF24L01 с контрльным модулем на жилом этаже (чтобы каждый раз когда вдруг не идет вода из крана, не бежать в котельную)
Может причина в том, что цикл начинается из состояния 0? В состоянии 0 предполагается, что таймер 3ч уже запущен. Надо либо запускать таймер в setup(), либо начинать цикл из состояния 1.
убрал пост, новый код ниже
убрал пост, новый код ниже
отлично... начал смотреть код библиотеки и нашел я ошибку - я проверяю включен таймер или нет, а надо проверять, был ли он переполнен или нет
т.е. вот так надо
Ну, вроде все работает.
Пойду почитаю про классы (чего в public, а чего нет), попробую-таки функции вынести в библиотеку (пока безуспешно) и потом поприкручиваю дисплейчик :)
Привет!
Внимательно просмотрел проект. Как-то сложноват он мне показался :(
Я бы не стал ждать, когда воды останется на 15 мин, а, допустим, постоянно подпитывал основной бак при снижении уровня примерно менее 50% V. Не знаю как у вас с электричеством, но пока оно есть, лучше заполнить бак доверху.
Для контроля работоспособности насоса и переполнения бака я себе закупил (поставлю по весне) реле ПОтока. Иногда называется реле ПРОтока. Такие реле бывают и для сильно загрязненной среды. Гугл/Али в помощь.
Может, инфа пригодится.
Удачи.
Олег, и тебе привет. Спасибо за советы.
Про сложность... ну да, есть такой момент. Это я еще дисплей не прикрутил :) Шучу.
Про подкачку воды. У меня есть некоторая идея - лучше выкачать воду, а потом ее закачать, чем она будет постоянно в баке. Некоторый обмен, снижающий риск застоя. Но это теория. На практике - залив сверху, забор снизу. Так что это просто некоторое внутренее желание. Хочу, чтобы вода сначала почти вся ушла из бака, а потом залилась новая.
Перед отъездом на зиму я уже погонял водопровод в ручном режиме. Т.е. бак наполнял вручную. Трехходовой вентиль включил, насос включил, 15 минут подождал, вентиль выключил, бак накачал, насос выключил :)
И вот мой опыт показывает, что при разборе воды из дома скорость наполнения емкости скваженным насосом такова, что не нужно никаких 15-ти минутных запасов воды. Вкачивает больше, чем разбирает. Так что нижний поплавок буду ставить сантиметрах в 10-15 ото дна.
Что касается электричества - бак в котельной в цоколе, без электричества насосная станция ничего по дому не раздаст, самотек невозможен (только то, что выдавид 100 литровый гидроаккумулятор). А если я генератор включаю, то какая разница? А если лефтричества нет долго, я его полюбому включу.
Относительно реле потока (или протока). Я не хочу дожидаться, пока вода пойдет в переливную трубу. Зачем? Поплавковый выключатель (продублированный на всякий случай) вполне себе вариант. А учитывая, что насос останавливается другим поплавком, то вообще предположить, что вода перельется - ну меньше 1%. А на этот процент как раз труба перелива.
Думаю, можно еще усложнить программу и прикрутить таймер, что если насос не выключается в течении 15-ти минут (нравится мне это количество, что уж тут, но можно и 25 :) ) - выключить принудительно и дать аварийную сигнализацию.
Навскидку такая схема получилась:
Вполне возможно,что я не совсем не прав.
PS. Картинка сделана в MS Visio,но какая-то серая :(
PPS. Не получается вставить pdf.
По моим соображениям, у твоей системы всего три основных состояния.
Ну и кучка дополнительных.
Опять-таки, на мой взгляд, получается два таймера, два уровнемера.
И еще на схеме забыл вставить запуск таймера по заполнению бака.
Как-то так.
Я тоже бросился было сначала код писать, но потом докумекал, что лучше сначала общий алгоритм прописать. Псоле ряда неудачных попыток остановился на опции "Фигуры горизонтальной функциональной блок-схемы" из меню Бизнес-процессы.
Как-то так.
круто! спасибо за участие
единственное - картинка очень маленького разрешения, практически ничего не видно, кинь если не сложно на почту bob_shmidt ну там значек собаки и это все на mail.ru
про логику, дык ты посмотри на предыдущей странице темы у нас с Andy был целый эпос начиная с этого сообщения и с блок схемами и т.д. и т.п.
Вроде, исходник картинки беру высокого качества, но где-то внутри оно пережимается :(
Сейчас скину на почту.
PS. Я всю вашу ветку смотрел.
Очень тяжело читать эту тему, много развернутого кода и неформатных картинок, пожалуйста прочитайте эти посты
Пост для кода, самый первый (как свернуть код и другое)
Пост для картинок (без потери качества изображений!!!!!) пост 18
причесал тему слегка.
движок форума, конечно, не совсем мне понятен. некоторые мои посты я не могу отредактировать, нет такой "кнопки" (видимо это просиходит, если не просто написать новый пост, а нажатьь "ответить")
не понимаю, как удалить отдельный пост, приходится писать "заглушки"
очень жалко, что нет механизма личных сообщений...
Это конечно, смешно, но прошло больше, чем год


)
Когда я сел вспоминать, что я там наваял столько времени спустя, даже учитывая мою почти параноидальную склонность комментировать очевидные вещи, я с трудом справился
Поскольку задача передо мной сейчас была сугубо практическая - таки запустить автоматику, я решил оставить в стороне всякие излишества, типа дисплея (через неделю потеряшек в менюшках, отложил), типа часов реального времени (китайский шедевр при отключении упорно выдавал 0,6в с рабочей батарейки с ожидаемым сбросом времени), записи на SD (я уже и не вспомнил, что я таки хотел записывать
Итак, вчера я все запустил. Работает. Вместо дисплея - 7 led-ов. Но, конечно, есть ряд нареканий и поводов к улучшению.
1. Логика кода была так жестко завязана на состояние поплавков в жесткой связке с светодиодами, что попытки поменять логику "мигания" подвела меня к необходимости вообще пересмотреть сам принцип сигнализации состояний. Иначе ничего не выходит.
2. При первом включении системы по умолчанию запускается полный цикл с прокачкой скважины и т.д. Но состояние поплавков считывается уже после того, как проходит цикл анализа состояния - в результате, даже если бак полный, полный цикл стартует с риском перелива (сегодня проверю, так ли это). Но почему и где это происходит - загадка. В своем же коде не могу разобраться
Попробую вообще с чистого листа начать.
Ну и плюшки на будущее.
1. Я хотел бы все-таки прикрутить сдвиговый регистр на вход (на выход уже работает). Пока не успешно.
2. Считывать состояние вентиля (там есть концевики), убрав один таймер.
3. Есть потребность летом один раз в сутки по любому прокачивать скважину, наполняя технический пруд.
4. Заказал на Али ультрасоник, очень уж хочется знать точно, сколько воды в баке. А то я его в пенал из ЭППС запаковал (иначе конденсатом заливает пол жестко) - ну и ничего не видно.
5. Дисплей, часы и SD
На память себе код
В догонку.
Перелива нет, если после подачи напряжения с полным баком нчинается полный цикл, то сначала идет прокачка на улицу, потом в дом и сразу же срабатывает отключение по верхнему поплавку.
Так что пока полет нормальный, всем доволен.
Не уверен, что в ближайшее время полезу что-то там менять. И так дел куча :)
Прошу прощения что вторгаюсь в Вашу тему но хочю предложить варианты работы насоса (у меня он работает в колодце с малым дебетом воды) без ардуино стоимомтью 50 центов а дальше( заисит только от потребляеьой нагрузки) в файле насос есть две схемы одна на реле вторая на оптопарах работа схеты на реле при включении устройства если верхний датчик находится в воде (7) ток через открытый транзистор включает реле и замыкает ево же контакты так как контакты нижнего датчика (8) находятся в воде ток через контакты реле самоблокирует реле до тех пор пока вода не опустится ниже контактов нижнего уровня. Цепь разомкнется и будет ждать контакта на верхнем уровне (схема представлена для электродных датчиков (я использовал стержни от батареек так как они наименее подвержны электролизу при постоянном токе) На схеме обозначено одно реле с одной групой контактов. Для комутации высокого напряжения необходимо второе реле которе подключается паралельно первому или если применять одно то с двумя группами контактов Цена только от стоимости реле На второй схеме практически тот же принцип но с использованием оптопар Я использовал самую рпспространенную РС817 и МОС30,,,, причем МОС30.... это уже управление нагрузкой (его также можно заменить на реле или с его выводов включив симистор управлять более мошной нагрузкой). И цена ниже и габариты Транзисторы могут преминятся любые на напряжение источника питания я применял КТ315В Г также о второй схеме необжодимо увеличить сопротивление резисторов при увелечении напряжения
схемы и многое другое можнонайтм по ссылке
http://flprog.ru/forum/18-2165-2
базиба :)
как обычно, спустя год .... :)
все до сих пор работает. Из реально актуальных вопросов к доработке только один - таймер по началу закачивания бака. И то только потому, что сделал переключение в ручной режим и вентиль, переводящий вывод насоса на поли. И этот самый вентиль в котельной :/
Окрываешь вентиль на полив, включаешь вручную насос - пошел поливать. Устал, выключил насос, забыл перекрыть вентиль. Включилась автоматика - в котельной все поплыло...
Но сейчас я занялся автоматической кормушкой для кур, это поактуальнее, позже выложу проектик.
Спустя 4 годя я дозрел-таки до переделки автоматики.
Основные задачи (на память):
1. Все временные интервалы должны быть настраиваемые а не записаны намертво.
2. Добавить обработку концевых замыкателей 3-х ходового вентиля
3. Таки дисплей
4. RTC DS3231
5. Добавить связь по nRF24L01 с контрльным модулем на жилом этаже (чтобы каждый раз когда вдруг не идет вода из крана, не бежать в котельную)
Сейчас заканчиваю разводку новой платы в KiCAD