合并面板按键类

This commit is contained in:
大石头X2 2017-02-28 22:35:27 +08:00
parent 4ef42d15a4
commit a259dafbca
5 changed files with 46 additions and 265 deletions

View File

@ -1,7 +1,5 @@
#include "Button.h"
InputPort Button::ACZero;
int Button::ACZeroAdjTime = 2300;
#include "ACZero.h"
Button::Button()
{
@ -9,8 +7,7 @@ Button::Button()
Index = 0;
_Value = false;
//_Handler = nullptr;
//_Param = nullptr;
Zero = nullptr;
}
Button::~Button()
@ -25,11 +22,8 @@ void Button::Set(Pin key, Pin led, Pin relay)
void Button::Set(Pin key, Pin led, bool ledInvert, Pin relay, bool relayInvert)
{
Key.Set(key);
//Key.Register(OnPress, this);
//Key.Press = OnPress;
Key.Press.Bind(&Button::OnPress, this);
Key.UsePress();
//Key.Register(Delegate2<InputPort&, bool>(&Button::OnPress, this))
Key.Open();
if (led != P0)
@ -44,12 +38,6 @@ void Button::Set(Pin key, Pin led, bool ledInvert, Pin relay, bool relayInvert)
}
}
/*void Button::OnPress(InputPort* port, bool down, void* param)
{
Button* btn = (Button*)param;
if(btn) btn->OnPress(port->_Pin, down);
}*/
void Button::OnPress(InputPort& port, bool down)
{
// 每次按下弹起,都取反状态
@ -57,25 +45,10 @@ void Button::OnPress(InputPort& port, bool down)
{
SetValue(!_Value);
//if(_Handler) _Handler(this, _Param);
Press(*this);
}
}
/*void Button::Register(EventHandler handler, void* param)
{
if(handler)
{
_Handler = handler;
_Param = param;
}
else
{
_Handler = nullptr;
_Param = nullptr;
}
}*/
bool Button::GetValue() { return _Value; }
int Button::OnWrite(byte data)
@ -98,24 +71,11 @@ String Button::ToString() const
return str;
}
bool CheckZero(const InputPort& port)
{
int retry = 200;
while (!port.Read() && retry-- > 0) Sys.Delay(100); // 检测下降沿 先去掉低电平 whileio==false
if (retry <= 0) return false;
retry = 200;
while (port.Read() && retry-- > 0) Sys.Delay(100); // 当检测到 高电平结束 就是下降沿的到来
if (retry <= 0) return false;
return true;
}
void Button::SetValue(bool value)
{
if (!ACZero.Empty())
if (Zero)
{
if (CheckZero(ACZero)) Sys.Delay(ACZeroAdjTime);
Sys.Sleep(Zero->Time);
// 经检测 过零检测电路的信号是 高电平12ms 低电平7ms 即下降沿后8.5ms 是下一个过零点
// 从给出信号到继电器吸合 测量得到的时间是 6.4ms 继电器抖动 1ms左右 即 平均在7ms上下
@ -127,21 +87,3 @@ void Button::SetValue(bool value)
_Value = value;
}
bool Button::SetACZeroPin(Pin aczero)
{
auto& port = ACZero;
// 该方法可能被初级工程师多次调用,需要检查并释放旧的,避免内存泄漏
if (!port.Empty()) port.Close();
port.Set(aczero).Open();
// 需要检测是否有交流电,否则关闭
if (CheckZero(port)) return true;
port.Close();
port.Clear();
return false;
}

View File

@ -5,14 +5,13 @@
#include "Device\Port.h"
#include "Message\DataStore.h"
class ACZero;
// 面板按钮
class Button : public ByteDataPort
{
private:
void OnPress(InputPort& port, bool down);
public:
cstring Name; // 按钮名称
cstring Name; // 按钮名称
int Index; // 索引号,方便在众多按钮中标识按钮
InputPort Key; // 输入按键
@ -21,7 +20,8 @@ public:
Delegate<Button&> Press; // 按下事件
public:
ACZero* Zero; // 交流电过零检测
// 构造函数。指示灯和继电器一般开漏输出,需要倒置
Button();
virtual ~Button();
@ -29,25 +29,17 @@ public:
void Set(Pin key, Pin led = P0, bool ledInvert = true, Pin relay = P0, bool relayInvert = true);
void Set(Pin key, Pin led, Pin relay);
bool GetValue();
void SetValue(bool value);
virtual void SetValue(bool value);
virtual int OnWrite(byte data);
virtual byte OnRead();
String ToString() const;
// 过零检测
private:
static int ACZeroAdjTime; // 过零检测时间补偿 默认 2300us
public:
static InputPort ACZero; // 交流过零检测引脚
static bool SetACZeroPin(Pin aczero); // 设置过零检测引脚
static void SetACZeroAdjTime(int us){ ACZeroAdjTime = us; }; // 设置 过零检测补偿时间
private:
bool _Value; // 状态
virtual void OnPress(InputPort& port, bool down);
};
#endif

View File

@ -30,50 +30,16 @@ Button_GrayLevelConfig::Button_GrayLevelConfig()
OffGrayLevel = 20;
}
InputPort* Button_GrayLevel::ACZero = nullptr;
int Button_GrayLevel::ACZeroAdjTime = 2300;
Button_GrayLevel::Button_GrayLevel() : ByteDataPort()
Button_GrayLevel::Button_GrayLevel() : Button()
{
#if DEBUG
Name = nullptr;
#endif
Index = 0;
_Value = false;
_Pwm = nullptr;
_Channel = 0;
//_Handler = nullptr;
//_Param = nullptr;
EnableDelayClose = true;
_tid = 0;
Next = 0xFF;
}
void Button_GrayLevel::Set(Pin key, Pin relay, bool relayInvert)
{
Key.Set(key);
// 中断过滤模式
//Key.Mode = InputPort::Both;
Key.ShakeTime = 20;
//Key.Register(OnPress, this);
Key.Press.Bind(&Button_GrayLevel::OnPress, this);
Key.HardEvent = true;
Key.UsePress();
Key.Open();
//面板事件
if (!_task3)
{
_task3 = Sys.AddTask(&Button_GrayLevel::ReportPress, this, -1, -1, "面板事件");
}
if (relay != P0) Relay.Init(relay, relayInvert).Open();
}
void Button_GrayLevel::Set(Pwm* drive, byte pulseIndex)
{
if (drive && pulseIndex < 4)
@ -84,6 +50,11 @@ void Button_GrayLevel::Set(Pwm* drive, byte pulseIndex)
// 刷新输出
RenewGrayLevel();
}
//面板事件
if (!_task3)
{
_task3 = Sys.AddTask(&Button_GrayLevel::ReportPress, this, -1, -1, "面板事件");
}
}
void Button_GrayLevel::RenewGrayLevel()
@ -118,12 +89,6 @@ void Button_GrayLevel::GrayLevelDown()
}
}
/*void Button_GrayLevel::OnPress(InputPort* port, bool down, void* param)
{
Button_GrayLevel* btn = (Button_GrayLevel*)param;
if (btn) btn->OnPress(port, down);
}*/
void Button_GrayLevel::OnPress(InputPort& port, bool down)
{
//只有弹起才能执行业务动作
@ -174,9 +139,9 @@ void Button_GrayLevel::ReportPress()
Press(*this);
}
void Close2Task(void * param)
void Button_GrayLevel::OnDelayClose()
{
auto bt = (Button_GrayLevel *)param;
auto bt = this;
bt->GrayLevelUp();
if (bt->delaytime > 1000)
{
@ -186,9 +151,10 @@ void Close2Task(void * param)
else
{
bt->delaytime = 0;
debug_printf("延时关闭已完成 删除任务 %p\r\n", bt->_task2);
Sys.RemoveTask(bt->_task2);
bt->_task2 = 0;
Sys.SetTask(bt->_task2, false);
bt->SetValue(false);
bt->Key.PressTime = 0;
bt->Press(*bt); // 维护数据区状态
@ -199,81 +165,22 @@ void Close2Task(void * param)
void Button_GrayLevel::DelayClose2(int ms)
{
if (!_task2 && ms)
{
_task2 = Sys.AddTask(Close2Task, this, 0, 1000, "延时关闭");
}
if (ms == 0)return;
if (!_task2) _task2 = Sys.AddTask(&Button_GrayLevel::OnDelayClose, this, -1, -1, "延时关闭");
Sys.SetTask(_task2, true, 0);
delaytime = ms;
}
int Button_GrayLevel::OnWrite(byte data)
{
SetValue(data > 0);
return OnRead();
}
byte Button_GrayLevel::OnRead()
{
return _Value ? 1 : 0;
}
bool Button_GrayLevel::GetValue() { return _Value; }
bool CheckZero(InputPort* port)
{
// 过零检测代码有风险 强制执行喂狗任务确保不出问题
//auto dog = Task::Scheduler()->FindTask(WatchDog::FeedDogTask);
//if(dog) dog->Execute(Sys.Ms());
// 检测下降沿 先去掉低电平 whileio==false
int retry = 200;
while (*port == false && retry-- > 0) Sys.Delay(100);
if (retry <= 0) return false;
// 喂狗
Sys.Sleep(1);
// 当检测到 高电平结束 就是下降沿的到来
retry = 200;
while (*port == true && retry-- > 0) Sys.Delay(100);
if (retry <= 0) return false;
return true;
}
void Button_GrayLevel::SetValue(bool value)
{
_Value = value;
if (ACZero && ACZero->Opened)
{
if (CheckZero(ACZero)) Sys.Delay(ACZeroAdjTime);
// 经检测 过零检测电路的信号是 高电平12ms 低电平7ms 即下降沿后8.5ms 是下一个过零点
// 从给出信号到继电器吸合 测量得到的时间是 6.4ms 继电器抖动 1ms左右 即 平均在7ms上下
// 故这里添加1ms延时
// 这里有个不是问题的问题 一旦过零检测电路烧了 开关将不能正常工作
}
Relay = value;
Button::SetValue(value);
RenewGrayLevel();
}
bool Button_GrayLevel::SetACZeroPin(Pin aczero)
{
// 该方法需要检查并释放旧的,避免内存泄漏
if (!ACZero) ACZero = new InputPort(aczero);
// 需要检测是否有交流电,否则关闭
if (CheckZero(ACZero)) return true;
ACZero->Close();
return false;
}
void Button_GrayLevel::Init(TIMER tim, byte count, Button_GrayLevel* btns, TAction onpress, const ButtonPin* pins, byte* level, const byte* state)
{
debug_printf("\r\n初始化开关按钮 \r\n");
@ -311,7 +218,7 @@ void Button_GrayLevel::Init(TIMER tim, byte count, Button_GrayLevel* btns, TActi
// 配置 Button 主体
for (int i = 0; i < count; i++)
{
btns[i].Set(pins[i].Key, pins[i].Relay, pins[i].Invert);
btns[i].Set(pins[i].Key, P0, false, pins[i].Relay, pins[i].Invert);
}
#if DEBUG
@ -335,38 +242,6 @@ void Button_GrayLevel::Init(TIMER tim, byte count, Button_GrayLevel* btns, TActi
}
}
void ACZeroReset(void *param)
{
InputPort* port = Button_GrayLevel::ACZero;
if (port)
{
//Sys.Reboot();
debug_printf("定时检查过零检测\r\n");
// 需要检测是否有交流电,否则关闭
if (CheckZero(port)) return;
port->Close();
}
}
void Button_GrayLevel::InitZero(Pin zero, int us)
{
if (zero == P0) return;
debug_printf("\r\n过零检测引脚PB12探测\r\n");
Button_GrayLevel::SetACZeroAdjTime(us);
if (Button_GrayLevel::SetACZeroPin(zero))
debug_printf("已连接交流电!\r\n");
else
debug_printf("未连接交流电或没有使用过零检测电路\r\n");
debug_printf("所有开关按钮准备就绪!\r\n\r\n");
Sys.AddTask(ACZeroReset, nullptr, 60000, 60000, "定时过零");
}
Button_GrayLevelConfig Button_GrayLevel::InitGrayConfig()
{
static Button_GrayLevelConfig cfg;

View File

@ -2,9 +2,9 @@
#define __BUTTON_GRAY_LEVEL_H__
#include "Config.h"
#include "Device\Port.h"
#include "Device\Pwm.h"
#include "Message\DataStore.h"
#include "Button.h"
struct ButtonPin
{
@ -25,7 +25,7 @@ public:
};
class Button_GrayLevel;
using TAction = Delegate<Button_GrayLevel&>::TAction;
using TAction = Delegate<Button&>::TAction;
// 面板按钮
// 这里必须使用_packed关键字生成对齐的代码否则_Value只占一个字节导致后面的成员进行内存操作时错乱
@ -33,41 +33,27 @@ using TAction = Delegate<Button_GrayLevel&>::TAction;
// 干脆把_Value挪到最后解决问题
extern Button_GrayLevelConfig* ButtonConfig;
class Button_GrayLevel : public ByteDataPort
class Button_GrayLevel : public Button
{
public:
int Index; // 索引号,方便在众多按钮中标识按钮
#if DEBUG
cstring Name; // 按钮名称
#endif
InputPort Key; // 输入按键
OutputPort Relay; // 继电器
// 外部设置模式调用
typedef bool(*IOHandler)(Button_GrayLevel* bt, bool down, void * param);
IOHandler ExterSet = nullptr;
void * ExterSetParam = nullptr;
public:
bool EnableDelayClose; // 标识是否启用延时关闭功能,默认启用
Delegate<Button_GrayLevel&> Press;
// 构造函数。指示灯和继电器一般开漏输出,需要倒置
Button_GrayLevel();
static Button_GrayLevelConfig InitGrayConfig();
void Set(Pin key, Pin relay = P0, bool relayInvert = true);
using Button::Set;
// led 驱动器设置
void Set(Pwm* drive, byte pulseIndex);
bool GetValue();
void SetValue(bool value);
virtual void SetValue(bool value);
void RenewGrayLevel();
//virtual int Write(byte* pcmd); // 重载 ByteDataPort 的函数 自定义 Delay Flush Open Close
//virtual int Read(byte* cmd);
virtual int OnWrite(byte data);
virtual byte OnRead();
public:
static void Init(TIMER tim, byte count, Button_GrayLevel* btns, TAction onpress, const ButtonPin* pins, byte* level, const byte* state);
static void UpdateLevel(byte* level, Button_GrayLevel* btns, byte count);
private:
// 指示灯灰度驱动器 Pwm;
@ -77,33 +63,19 @@ private:
bool _Value; // 状态
ushort Reserved; // 补足对齐问题
//static void OnPress(InputPort* port, bool down, void* param);
void OnPress(InputPort& port, bool down);
public:
static void Init(TIMER tim, byte count, Button_GrayLevel* btns, TAction onpress, const ButtonPin* pins, byte* level, const byte* state);
static void InitZero(Pin zero, int us = 2300);
static void UpdateLevel(byte* level, Button_GrayLevel* btns, byte count);
virtual void OnPress(InputPort& port, bool down);
void GrayLevelDown();
void GrayLevelUp();
void DelayClose2(int ms); // 自定义延时关闭
int delaytime = 0;
uint _task2 = 0;
void OnDelayClose();
//上报状态变化
uint _task3 = 0;
void ReportPress();
// 过零检测
private:
static int ACZeroAdjTime; // 过零检测时间补偿 默认 2300us
public:
static InputPort* ACZero; // 交流过零检测引脚
static bool SetACZeroPin(Pin aczero); // 设置过零检测引脚
static void SetACZeroAdjTime(int us) { ACZeroAdjTime = us; }; // 设置 过零检测补偿时间
};
#endif

View File

@ -234,7 +234,7 @@ bool CheckUserPress(InputPort* port, bool down, void* param)
return false;
}
void CheckUserPress3(Button_GrayLevel& btn)
void CheckUserPress3(Button& btn)
{
CheckUserPress(&btn.Key, btn.Key.Read(), nullptr);
}