ich tüftle seit einiger Zeit an einem Gardinenaktor für eine IKEA Hugad Gardinenstange. Idee des ganzen ist, die gesamte Platine mit Batterien in der Gardinenstange verschwinden zu lassen und 3D gedruckte Endkappen zu verwenden, um ein Nylonseil umlaufen zu lassen, welches die Gardinen mithilfe eines kleinen Getriebemotors öffnet oder schließt.
Die Erkennung der Endpositionen wird mithilfe von zwei Magnetschlitten und zwei Reed-Schalten realisiert. Die Platine ist als Prototyp gestaltet, bestellt und bestückt. Die 3D-Teile sind in Produktion.
Ich habe den bereits vorhandenen Sketch für einen Rollladenaktor https://github.com/pa-pa/AskSinPP/tree/ ... -LC-Bl1-FM für meinen Aktor anpassen.
Der Sketch funktioniert so weit, der Motor bewegt sich in die gewünschte Richtung, der Aktor wird erkannt und lässt sich einstellen.
Jetzt aber zu meinen Problemen, bei denen mir vielleicht jemand hier helfen kann.
- Durch die Interrupts wird der Motor (die Gardine) an seiner Endpostion gestoppt. Ist einer der beiden Endschalter bereits geschlossen, bewegt sich der Motor auch korrekterweise nicht mehr. Das Level wird auch dann korrekt an die CCU gesendet. Trotzdem scheint die BlineStateMachine im Hintergrund weiterzulaufen (In der CCU ist weiterhin das Zahnrad bei "Letzte Änderung" zu sehen). Drückt man in der CCU die Stop Taste, wird auf einmal ein anderes Level zurückgemeldet. Gibt es irgendeine Möglichkeit die BlindeStateMachine beim Erreichen eines Endschalter vollständig zu stoppen. Weiterhin gibt es in der CCU für den Aktor die Einstellung "Anzahl der Fahrten bis zur automatischen Referenzfahrt". Könnte man die beiden Endschalter zu Referenzierung benutzen, sodass der Aktor die Fahrzeit selbstständig lernt?
- Da es sich bei dem Projekt um einen Batterieaktor handelt, würde ich den Aktor gerne in den Sleep Modus versetzen und per WOR aufwachen lassen. Ich habe das Beispiel aus dem AskSinPP Projekt herangezogen und die entsprechenden Codezeilen in meinen Sketch integriert. Setze ich den SAVEPWR_MODE jedoch zu Sleep<> bekomme ich den Aktor nicht aufgeweckt. Hat hier jemand eine Idee, woran das liegen könnte? Muss der CCU aktiv mitgeteilt werden, dass ein Aktor WOR benutzt (bspw. duch custom RFTypes)?
Viele Grüße
Code: Alles auswählen
#define EI_NOTEXTERNAL
#define NORTC
#define USE_WOR
// #define NDEBUG
#include <EnableInterrupt.h>
#include <AskSinPP.h>
#include <LowPower.h>
#include <Blind.h>
#include "tmBattery.h"
/**
* Define the used pins, power saving mode and available peers per channel
*/
#define LED_PIN 4
#define CONFIG_BUTTON_PIN 8
#define MOTOR_ENABLE 5
#define MOTOR_DIR 3
#define MOTOR_VCC 9
#define CLOSE_SWITCH 7
#define OPEN_SWITCH 6
#define SAVEPWR_MODE Idle<>
#define PEERS_PER_CHANNEL 12
/**
* Define the device info
*/
using namespace as;
const struct DeviceInfo PROGMEM devinfo = {
{0x62, 0x51, 0x01}, // Device ID
"EXP625BL01", // Device Serial
{0x00,0x05}, // Device Model
0x10, // Firmware Version
as::DeviceType::BlindActuator, // Device Type
{0x01,0x00} // Info Bytes
};
/**
* Configure the used hardware
*/
typedef AvrSPI<10,11,12,13> RadioSPI;
typedef Radio<RadioSPI , 2> RadioType;
typedef StatusLed<LED_PIN> LedType;
typedef tmBatteryResDiv<A0, A2, 3102> BatteryType;
typedef AskSin<LedType,BatteryType,RadioType> Hal;
Hal hal;
DEFREGISTER(BlindReg0,MASTERID_REGS,DREG_INTKEY,DREG_CONFBUTTONTIME,DREG_LOCALRESETDISABLE, DREG_LOWBATLIMIT)
class BlindList0 : public RegList0<BlindReg0> {
public:
BlindList0 (uint16_t addr) : RegList0<BlindReg0>(addr) {}
void defaults () {
clear();
// intKeyVisible(false);
confButtonTime(0xff);
// localResetDisable(false);
}
};
class BlChannel : public ActorChannel<Hal,BlindList1,BlindList3,PEERS_PER_CHANNEL,BlindList0,BlindStateMachine> {
public:
typedef ActorChannel<Hal,BlindList1,BlindList3,PEERS_PER_CHANNEL,BlindList0,BlindStateMachine> BaseChannel;
static BlChannel* instance;
BlChannel () {}
virtual ~BlChannel () {}
virtual void switchState(uint8_t oldstate,uint8_t newstate, uint32_t stateDelay) {
BaseChannel::switchState(oldstate, newstate, stateDelay);
if( newstate == AS_CM_JT_RAMPON && stateDelay > 0) {
if (!digitalRead(OPEN_SWITCH)) {
DPRINTLN("Already Open");
openSwitchTrigger();
} else {
motorOpen();
}
}
else if( newstate == AS_CM_JT_RAMPOFF && stateDelay > 0) {
motorClose();
if (!digitalRead(CLOSE_SWITCH)) {
DPRINTLN("Already Closed");
closeSwitchTrigger();
} else {
motorClose();
}
}
else {
motorStop();
}
}
static void openSwitchTrigger () {
DPRINTLN("Open Switch Trigger");
disableInterrupt(OPEN_SWITCH | PINCHANGEINTERRUPT);
if (BlChannel::instance != nullptr) {
BlChannel::instance->setState(AS_CM_JT_OFF, DELAY_INFINITE);
BlChannel::instance->updateLevel(200);
}
}
static void closeSwitchTrigger () {
DPRINTLN("Close Switch Trigger");
disableInterrupt(CLOSE_SWITCH | PINCHANGEINTERRUPT);
if (BlChannel::instance != nullptr) {
BlChannel::instance->setState(AS_CM_JT_OFF, DELAY_INFINITE);
BlChannel::instance->updateLevel(0);
}
}
void motorOpen () {
DPRINTLN("Opening Curtain");
digitalWrite(MOTOR_VCC,HIGH);
digitalWrite(MOTOR_DIR,HIGH);
digitalWrite(MOTOR_ENABLE,HIGH);
enableInterrupt(OPEN_SWITCH | PINCHANGEINTERRUPT, openSwitchTrigger, FALLING);
}
void motorClose () {
DPRINTLN("Closing Curtain");
digitalWrite(MOTOR_VCC,HIGH);
digitalWrite(MOTOR_DIR,LOW);
digitalWrite(MOTOR_ENABLE,HIGH);
enableInterrupt(CLOSE_SWITCH | PINCHANGEINTERRUPT , closeSwitchTrigger, FALLING);
}
void motorStop () {
DPRINTLN("Stopping Curtain");
digitalWrite(MOTOR_VCC,LOW);
digitalWrite(MOTOR_DIR,LOW);
digitalWrite(MOTOR_ENABLE,LOW);
disableInterrupt(CLOSE_SWITCH | PINCHANGEINTERRUPT);
disableInterrupt(OPEN_SWITCH | PINCHANGEINTERRUPT);
}
void init () {
instance = this;
pinMode(MOTOR_DIR,OUTPUT);
pinMode(MOTOR_ENABLE,OUTPUT);
pinMode(MOTOR_VCC,OUTPUT);
pinMode(OPEN_SWITCH,INPUT_PULLUP);
pinMode(CLOSE_SWITCH,INPUT_PULLUP);
motorStop();
BaseChannel::init();
}
};
/**
* Setup the device with channel type and number of channels
*/
typedef MultiChannelDevice<Hal,BlChannel,1,BlindList0> BlindType;
BlindType sdev(devinfo,0x20);
ConfigButton<BlindType> cfgBtn(sdev);
InternalButton<BlindType> btnup(sdev,1);
InternalButton<BlindType> btndown(sdev,2);
BurstDetector<Hal> bd(hal);
void initPeerings (bool first) {
// create internal peerings - CCU2 needs this
if(first) {
sdev.channel(1).peer(btnup.peer(),btndown.peer());
}
}
BlChannel * BlChannel::instance = nullptr;
void setup () {
DINIT(9600,ASKSIN_PLUS_PLUS_IDENTIFIER);
//storage().setByte(0,0);
bool first = sdev.init(hal);
sdev.channel(1).init();
initPeerings(first);
buttonISR(cfgBtn,CONFIG_BUTTON_PIN);
bd.enable(sysclock);
hal.activity.stayAwake(seconds2ticks(15));
hal.initBattery(60UL * 60, 22, 19);
sdev.initDone();
}
void loop() {
bool worked = hal.runready();
bool poll = sdev.pollRadio();
if (!worked && !poll) {
if (hal.battery.critical()) {
hal.activity.sleepForever(hal);
}
hal.activity.savePower<SAVEPWR_MODE>(hal);
}
}