Ардуино для солнечных панелей

Добрый день! У меня задача написать скетч для ардуино уно для автоматического поворота солнечных панелей вслед за солнцем. Вся конструкция уже смонтирована и пока зафиксирована в стационарном положении. Поворот будет осуществляться с помощью актуатора со встроенным датчиком холла. Его я уже приобрел, у него такие характеристики: 24 V двигатель, направление движения штока меняется изменением полярности питания, в конечных точках автоостановка до смены полярности, время полного хода штока 750мм в холостую 40 сек, 4 провода с датчика холла (два из них- питание датчика 5V и два на сигнал), усилие 100 кг, 1 сигнал датчика на 1 оборот двигателя. Есть еще модуль реального времени DS1302 и 3 реле. Одно из реле под № 1 подает питание на двигатель актуатора, два других под номерами 2 и 3 меняют полярность на линии 24 V, для смены полярности нужно включить их оба.
Алгоритм работы такой: при включении установить шток в крайнее положение, далее получаем с модуля часов текущий час, находим сколько оборотов должен сделать двигатель в зависимости от текущего часа, включаем реле 1 до того момента, когда текущие обороты сравняются с количеством оборотов, найденным на предидущем шаге. Как только они сравнялись отключаем реле 1 и делаем паузу в 1 час. Это делаем в период с 9 до 16 часов. В 23 часа меняем полярность включив реле 2 и 3 (у них включение при напряжении на управляющем контакте 0, в отличии от реле 1, где нужно на управляющий контакт подать 5V) и включаем реле 1 на 40 сек для возврата штока в начальное положение. Далее пауза 10 часов, до 9-ти утра и так по циклу.
Я ни разу не программист, поэтому сразу решил, что закажу это дело фрилансерам, но после того, как меня там дважды просто развели на деньги пришлось самому попробовать разобраться. Пока получилось вот так:

#include<iarduino_RTC.h>//Подключаем библиотеку для работы с часами

iarduino_RTC time(RTC_DS1302, 8, 6, 7); //Назначаем пины модулю часов
const byte hallPin = 2; //контакт к которому подключен датчик холла
volatile long int rot;//переменная для хранения количества оборотов
const int ob9 = 134; //кол-во оборотов в 9часов
const int ob10 = 254; //кол-во оборотов в 10часов
const int ob11 = 367; //кол-во оборотов в 11часов
const int ob12 = 420; //кол-во оборотов в 12часов
const int ob13 = 378; //кол-во оборотов в 13часов
const int ob14 = 272; //кол-во оборотов в 14часов
const int ob15 = 159; //кол-во оборотов в 15часов
const int ob16 = 74; //кол-во оборотов в 16часов
const int relay1Pin = 3; //Пин для первого реле
const int relay2Pin = 5; //Пин для второго реле
const int relay3Pin = 4; //Пин для третьего реле
const int pitHall = 9; //Пин питания датчика холла
void detect() { //функция-обработчик,которая вызывается во время прерывания
 rot++;
}


void setup() {
 pinMode(relay3Pin, OUTPUT); //пин реле 3 как выход
 pinMode(relay2Pin, OUTPUT); //пин реле 2 как выход
 pinMode(relay1Pin, OUTPUT); //пин реле 1 как выход
 digitalWrite(relay3Pin, LOW); //Включаем реле 3
 delay(100);
 digitalWrite(relay2Pin, LOW); //Включаем реле 2
 delay(100);
 digitalWrite(relay1Pin, HIGH); //Включаем реле 1
 delay(40000);//Задержка40сек
 digitalWrite(relay1Pin, LOW); //Выключаем реле 1
 delay(100);
 digitalWrite(relay2Pin, HIGH); //Выключаем реле 2
 delay(100);
 digitalWrite(relay3Pin, HIGH); //Выключаем реле 3
 delay(5000);
}

void loop() {
 rot = 0; //Обнуляем количество оборотов
 int h;//Переменная для хранения текущего часа
 int obStop;//Переменная для определения оборотов для отключения мотора
 pinMode(relay1Pin, OUTPUT); //пин реле 1 как выход
 pinMode(relay2Pin, OUTPUT); //пин реле 2 как выход
 pinMode(relay3Pin, OUTPUT); //пин реле 3 как выход
 pinMode(pitHall, OUTPUT); //пин питания датчика как выход
 time.begin();//Инициируем работу с модулем реального времени
 h = time.Hours; //Получаем текущий час
 if (h == 9) obStop = ob9; //Определяем нужное кол-во оборотов в зависимости от текущего часа
 else if (h == 10) obStop = (ob9 + ob10);
 else if (h == 11) obStop = (ob9 + ob10 + ob11);
 else if (h == 12) obStop = (ob9 + ob10 + ob11 + ob12);
 else if (h == 13) obStop = (ob9 + ob10 + ob11 + ob12 + ob13);
 else if (h == 14) obStop = (ob9 + ob10 + ob11 + ob12 + ob13 + ob14);
 else if (h == 15) obStop = (ob9 + ob10 + ob11 + ob12 + ob13 + ob14 + ob15);
 else if (h == 16) obStop = (ob9 + ob10 + ob11 + ob12 + ob13 + ob14 + ob15 + ob16);
 else obStop = 0;
 if (h >= 9 && h < 23) { // Если время от 9 до 23 часов
   digitalWrite(pitHall, HIGH); // Включаем питание датчика холла
   delay(100);
   pinMode(hallPin, INPUT_PULLUP); // настроим пин 2 на вход, с подтяжкой к питанию
   attachInterrupt(digitalPinToInterrupt(hallPin), detect, RISING); // активируем прерывание и свяжем его с функцией detect
   if (rot < obStop) digitalWrite(relay1Pin, HIGH);
   if (rot == obStop) digitalWrite(relay1Pin, LOW);
   rot = 0; // Обнуляем количество оборотов
   digitalWrite(pitHall, LOW); // Отключаем питание датчика
 }
 delay (3600000); // Ждем 1 час

 if (h == 23) {
   digitalWrite(relay3Pin, LOW); //Включаем реле 3
   delay(100);
   digitalWrite(relay2Pin, LOW); //Включаем реле 2
   delay(100);
   digitalWrite(relay1Pin, HIGH); //Включаем реле 1
   delay(40000);//Задержка40сек
   digitalWrite(relay1Pin, LOW); //Выключаем реле 1
   delay(100);
   digitalWrite(relay2Pin, HIGH); //Выключаем реле 2
   delay(100);
   digitalWrite(relay3Pin, HIGH); //Выключаем реле 3
 }
 delay (36000000); // Ждем 10 часов

}

Setup отрабатывает нормально, а вот дальше мне видимо без помощи не разобраться. Сразу после загрузки скетча шток уходит в начальное положение, текущий час видимо присваивается переменной h и вычисляется переменная obStop т.к. включается реле 1 и шток идет вперед. Но реле 1 не отключается и он не останавливается до самого крайнего переднего положения. При повторной загрузке скетча уже реле 1 не включается. Оказывается модуль часов сбрасывается в 0, причем так, что установить в нем время другим скетчем не удается пока его не отключишь от питания и не снимешь батарейку. После этого время удается залить, но до следующего запуска моего скетча, все повторяется.
Я думаю проблема в обработке сигнала датчика холла, видимо когда он выдает сигналы мой скетч не работает как я задумал, происходит что то для меня непонятное.
Помогите пожалуйста, кому не трудно разобраться.

Надо почитать про отладку и вставить в критических местах вывод переменных в Serial …

Начиная с 65 строуи надо поменять:

на:

А зачем инициировать работу с модулем часов в лупе, да еще при каждом проходе?

у вас каждый вход в луп обнуляет счетчик оборотов

Да, наверно зря я инициализацию в луп записал, просто боялся, что из сетапа может не сработает, поправлю.
Счетчик и должен быть нулевым сначала, иначе будет копиться и obStop будет меньше, чем rot.
Про отладку сейчас почитаю, спасибо.

Сейчас попробую, спасибо.

при каких условия рот станет отличным
от 0, актуатор должен иметь обороты 100 млн об сек

с таким подходом программистами не становятся

Ещё возможен вариант что от наводок реле/двигателя ваш скетч сбрасывается при переключениях/движении …

1 лайк

Как только двигатель начнет вращаться.

Сам двигатель далеко от платы, будет до него метров 30, сейчас лежит около 2-х метров.

какой смысл?

Дождаться когда rot будет равен obStop и отключить двигатель.

У меня нет задачи стать программистом, шестой десяток лет заканчивается.

Какая у вас широта ???

rot у вас обнуляется в строке 42 без всяких условий

58 градусов

у меня тоже, тем более такому серьезному мужчине стоит раобраться до конца раз уж взялся

Я просто подумал, что если его не обнулять, то в 23 часа он может суммироваться с предидущим.

delay у вас стоят без условий и выполнятся ОБА - хотя по логике сначала должен выполняться тот что на час несколько раз, а потом уже тот что на 10 часов …

Сначала вставьте:
в setup - Serial.println(F("Setup"));
в detect - Serial.println(rot);
в loop после h = time.Hours - Serial.print(F("h=")); Serial.println(h);

Будет видно как работает железо …
Если в терминал будет выведено более одного Setup - с железом БЕДА …