Всем привет. Я пытаюсь доработать вторую версию автокормушки для кошек. Хочу сделать к ней легкое приложение. Мой выбор пал на remotexy с подключением через bluetooth модуль. Накидала дизайн в remotexy, он его превратил в код и дальше я не понимаю как его правильно приспособить в исходный код кормушки. Буду рада любой помощи)
код с remotexy:
//////////////////////////////////////////////
// RemoteXY include library //
//////////////////////////////////////////////
// определение режима соединения и подключение библиотеки RemoteXY
#define REMOTEXY_MODE__SOFTSERIAL
#include <SoftwareSerial.h>
#include <RemoteXY.h>
// настройки соединения
#define REMOTEXY_SERIAL_RX 2
#define REMOTEXY_SERIAL_TX 3
#define REMOTEXY_SERIAL_SPEED 9600
// конфигурация интерфейса
#pragma pack(push, 1)
uint8_t RemoteXY_CONF[] =
{ 255,7,0,0,0,212,0,13,81,1,
1,0,26,74,12,12,2,31,208,158,
0,129,0,12,66,40,6,31,208,191,
208,190,208,180,208,176,209,135,208,176,
32,208,186,208,190,209,128,208,188,208,
176,0,129,0,11,11,42,6,65,208,
159,209,128,208,184,208,181,208,188,209,
139,32,208,191,208,184,209,137,208,184,
0,129,0,8,19,48,3,66,40,209,
131,209,129,209,130,208,176,208,189,208,
190,208,178,208,184,209,130,208,181,32,
208,178,209,128,208,181,208,188,209,143,
32,208,191,209,128,208,184,208,181,208,
188,208,190,208,178,32,208,191,208,184,
209,137,208,184,0,7,48,22,32,20,
5,31,26,2,7,48,22,41,20,5,
31,26,2,7,48,22,50,20,5,31,
26,2,129,0,17,23,34,3,66,32,
209,129,32,209,130,208,190,209,135,208,
189,208,190,209,129,209,130,209,140,209,
142,32,208,180,208,190,32,209,135,208,
176,209,129,208,190,208,178,41,0 };
// структура определяет все переменные и события вашего интерфейса управления
struct {
// input variables
uint8_t button_1; // =1 если кнопка нажата, иначе =0
int16_t edit_1; // 32767.. +32767
int16_t edit_2; // 32767.. +32767
int16_t edit_3; // 32767.. +32767
// other variable
uint8_t connect_flag; // =1 if wire connected, else =0
} RemoteXY;
#pragma pack(pop)
/////////////////////////////////////////////
// END RemoteXY include //
/////////////////////////////////////////////
void setup()
{
RemoteXY_Init ();
// TODO you setup code
}
void loop()
{
RemoteXY_Handler ();
// TODO you loop code
// используйте структуру RemoteXY для передачи данных
// не используйте функцию delay()
}
код основной:
// Клик - внеочередная кормёжка
// Удержание - задаём размер порции
const byte feedTime[][2] = {
{7, 0}, // часы, минуты. НЕ НАЧИНАТЬ ЧИСЛО С НУЛЯ
{12, 0},
{17, 0},
{21, 0},
};
#define EE_RESET 12 // любое число 0-255. Измени, чтобы сбросить настройки и обновить время
#define FEED_SPEED 3000 // задержка между шагами мотора (мкс)
#define BTN_PIN 2 // кнопка
#define STEPS_FRW 18 // шаги вперёд
#define STEPS_BKW 10 // шаги назад
const byte drvPins[] = {3, 4, 5, 6}; // драйвер (фазаА1, фазаА2, фазаВ1, фазаВ2)
// =========================================================
#include "EncButton.h"
#include <EEPROM.h>
#include <RTClib.h>
RTC_DS3231 rtc;
EncButton<BTN_PIN> btn;
int feedAmount = 100;
void setup() {
rtc.begin();
if (EEPROM.read(0) != EE_RESET) { // первый запуск
EEPROM.write(0, EE_RESET);
EEPROM.put(1, feedAmount);
rtc.adjust(DateTime(F([B]DATE[/B]), F([B]TIME[/B])));
}
EEPROM.get(1, feedAmount);
for (byte i = 0; i < 4; i++) pinMode(drvPins[i], OUTPUT); // пины выходы
}
void loop() {
static uint32_t tmr = 0;
if (millis() - tmr > 500) { // два раза в секунду
static byte prevMin = 0;
tmr = millis();
DateTime now = rtc.now();
if (prevMin != now.minute()) {
prevMin = now.minute();
for (byte i = 0; i < sizeof(feedTime) / 2; i++) // для всего расписания
if (feedTime[i][0] == now.hour() && feedTime[i][1] == now.minute()) // пора кормить
feed();
}
}
btn.tick();
if (btn.isClick()) {
feed();
}
if (btn.isHold()) {
int newAmount = 0;
while (btn.isHold()) {
btn.tick();
oneRev();
newAmount++;
}
disableMotor();
feedAmount = newAmount;
EEPROM.put(1, feedAmount);
}
}
void feed() {
for (int i = 0; i < feedAmount; i++) oneRev(); // крутим на количество feedAmount
disableMotor();
}
void disableMotor() {
for (byte i = 0; i < 4; i++) digitalWrite(drvPins[i], 0); // выключаем ток на мотор
}
void oneRev() {
static byte val = 0;
for (byte i = 0; i < STEPS_BKW; i++) runMotor(val--);
for (byte i = 0; i < STEPS_FRW; i++) runMotor(val++);
}
void runMotor(byte thisStep) {
/*static const byte steps[] = {0b1000, 0b1010, 0b0010, 0b0110, 0b0100, 0b0101, 0b0001, 0b1001};
for (byte i = 0; i < 4; i++)
digitalWrite(drvPins[i], bitRead(steps[thisStep & 0b111], i));
*/
static const byte steps[] = {0b1010, 0b0110, 0b0101, 0b1001};
for (byte i = 0; i < 4; i++)
digitalWrite(drvPins[i], bitRead(steps[thisStep & 0b11], i));
delayMicroseconds(FEED_SPEED);
}
encbutton.h:
#ifndef EncButton_h
#define EncButton_h
// =========== НАСТРОЙКИ ============
#define EB_FAST 30 // таймаут быстрого поворота
#define EB_DEB 80 // дебаунс кнопки
#define EB_HOLD 1000 // таймаут удержания кнопки
#define EB_STEP 500 // период срабатывания степ
#define EB_CLICK 400 // таймаут накликивания
// =========== НЕ ТРОГАЙ ============
#include <Arduino.h>
// флаг макро
#define _setFlag(x) (flags |= 1 << x)
#define _clrFlag(x) (flags &= ~(1 << x))
#define _readFlag(x) ((flags >> x) & 1)
// быстрое чтение пина
bool fastRead(const uint8_t pin) {
#if defined([B]AVR_ATmega328P[/B]) || defined([B]AVR_ATmega168[/B])
if (pin < 8) return bitRead(PIND, pin);
else if (pin < 14) return bitRead(PINB, pin - 8);
else if (pin < 20) return bitRead(PINC, pin - 14);
#elif defined([B]AVR_ATtiny85[/B]) || defined([B]AVR_ATtiny13[/B])
return bitRead(PINB, pin);
#elif defined(AVR)
uint8_t *_pin_reg = portInputRegister(digitalPinToPort(pin));
uint8_t _bit_mask = digitalPinToBitMask(pin);
return bool(*_pin_reg & _bit_mask);
#else
return digitalRead(pin);
#endif
return 0;
}
// класс
template < uint8_t S1, uint8_t S2 = 255, uint8_t KEY = 255 >
class EncButton {
public:
EncButton() {
if (S2 == 255) { // обычная кнопка
pinMode(S1, INPUT_PULLUP);
} else if (KEY == 255) { // энк без кнопки
pinMode(S1, INPUT_PULLUP);
pinMode(S2, INPUT_PULLUP);
} else { // энк с кнопкой
pinMode(S1, INPUT_PULLUP);
pinMode(S2, INPUT_PULLUP);
pinMode(KEY, INPUT_PULLUP);
}
}
void tick(bool hold = 0) {
uint32_t thisMls = millis();
uint32_t debounce = thisMls - _debTimer;
// обработка энка (компилятор вырежет блок если не используется)
if (S1 != 255 && S2 != 255) {
byte state = fastRead(S1) | (fastRead(S2) << 1); // получаем код
if (_readFlag(0) && state == 0b11) { // ресет и энк защёлкнул позицию
if (S2 == 255 || KEY != 255) { // энкодер с кнопкой
if (!_readFlag(4)) { // если кнопка не "удерживается"
if (_lastState == 0b10) EBState = (_btnState || hold) ? 3 : 1, counter++;
else if (_lastState == 0b01) EBState = (_btnState || hold) ? 4 : 2, counter--;
}
} else { // просто энкодер
if (_lastState == 0b10) EBState = 1, counter++;
else if (_lastState == 0b01) EBState = 2, counter--;
}
if (EBState != 0 && debounce < EB_FAST) _setFlag(1); // режим быстрого поворота
else _clrFlag(1);
_clrFlag(0);
_debTimer = thisMls;
}
if (state == 0b00) _setFlag(0);
_lastState = state;
}
// обработка кнопки (компилятор вырежет блок если не используется)
if (S2 == 255 || KEY != 255) {
if (S2 == 255) _btnState = !fastRead(S1); // обычная кнопка
if (KEY != 255) _btnState = !fastRead(KEY); // энк с кнопкой
if (_btnState) { // кнопка нажата
if (!_readFlag(3)) { // и не была нажата ранее
if (debounce > EB_DEB) { // и прошел дебаунс
_setFlag(3); // флаг кнопка была нажата
_debTimer = thisMls; // сброс таймаутов
EBState = 0; // сброс состояния
}
if (debounce > EB_CLICK) { // кнопка нажата после EB_CLICK
clicks = 0; // сбросить счётчик и флаг кликов
flags &= ~0b01100000;
}
} else { // кнопка уже была нажата
if (!_readFlag(4)) { // и удержание ещё не зафиксировано
if (debounce < EB_HOLD) { // прошло меньше удержания
if (EBState != 0) _setFlag(2); // но энкодер повёрнут! Запомнили
} else { // прошло больше времени удержания
if (!_readFlag(2)) { // и энкодер не повёрнут
EBState = 6; // значит это удержание (сигнал)
_setFlag(4); // запомнили что удерживается
_debTimer = thisMls; // сброс таймаута
}
}
} else { // удержание зафиксировано
if (debounce > EB_STEP) { // таймер степа
EBState = 7; // сигналим
_debTimer = thisMls; // сброс таймаута
}
}
}
} else { // кнопка не нажата
if (_readFlag(3)) { // но была нажата
if (debounce > EB_DEB && !_readFlag(4) && !_readFlag(2)) { // энкодер не трогали и не удерживали - это клик
EBState = 5;
clicks++;
}
flags &= ~0b00011100; // clear 2 3 4
_debTimer = thisMls; // сброс таймаута
} else if (clicks > 0 && debounce > EB_CLICK && !_readFlag(5)) flags |= 0b01100000; // флаг на клики
}
}
}
byte getState() { return EBState; }
void resetState() { EBState = 0; }
bool isFast() { return _readFlag(1); }
bool isTurn() { return (EBState > 0 && EBState < 5); }
bool isRight() { return checkState(1); }
bool isLeft() { return checkState(2); }
bool isRightH() { return checkState(3); }
bool isLeftH() { return checkState(4); }
bool isClick() { return checkState(5); }
bool isHolded() { return checkState(6); }
bool isHold() { return _readFlag(4); }
bool isStep() { return checkState(7); }
bool state() { return !fastRead(S1); }
bool hasClicks(byte numClicks) {
if (clicks == numClicks && _readFlag(6)) {
_clrFlag(6);
return 1;
}
return 0;
}
byte hasClicks() {
if (_readFlag(6)) {
_clrFlag(6);
return clicks;
} return 0;
}
int counter = 0;
byte clicks = 0;
private:
bool checkState(byte val) {
if (EBState == val) {
EBState = 0;
return 1;
} return 0;
}
uint32_t _debTimer = 0;
byte _lastState = 0, EBState = 0;
bool _btnState = 0;
byte flags = 0;
// flags
// 0 - enc reset
// 1 - enc fast
// 2 - enc был поворот
// 3 - флаг кнопки
// 4 - hold
// 5 - clicks flag
// 6 - clicks get
// 7 - reserved
// EBState
// 0 - idle
// 1 - right
// 2 - left
// 3 - rightH
// 4 - leftH
// 5 - click
// 6 - holded
// 7 - step
};
#endif
Изменено: