SmartOS/App/ACZero.cpp

111 lines
2.1 KiB
C++

#include "Kernel\Sys.h"
#include "Kernel\TTime.h"
#include "Device\Port.h"
#include "ACZero.h"
ACZero::ACZero()
{
Period = 10000;
Width = 0;
Count = 0;
}
ACZero::~ACZero()
{
if (Port.Opened) Close();
}
void ACZero::Set(Pin pin, byte invert)
{
if (pin == P0) return;
Port.HardEvent = true;
Port.Set(pin);
if (invert < 2) Port.Invert = invert;
Port.Press.Bind(&ACZero::OnHandler, this);
Port.UsePress();
}
bool ACZero::Open()
{
if (!Port.Open()) return false;
debug_printf("过零检测引脚探测: ");
// 等一次零点
Sys.Sleep(20);
if (Count > 0)
{
debug_printf("已连接交流电!\r\n");
}
else
{
debug_printf("未连接交流电!\r\n");
Port.Close();
return false;
}
return true;
}
void ACZero::Close()
{
Port.Close();
}
void ACZero::OnHandler(InputPort& port, bool down)
{
if (!down)
{
Width = port.PressTime;
return;
}
// 每256*10ms修正一次周期
if (Count++ > 0 && (Count & 0xFF) == 0)
{
// 两次零点
int us = Last.Elapsed();
// 零点信号可能有毛刺或者干扰,需要避开
//if (us <= Period / 2 || us >= Period * 2) return;
if (us <= (Period >> 1) || us >= (Period << 1)) return;
// 通过加权平均算法纠正数据
Period = (Period * 31 + us) / 32;
//debug_printf("OnHandler us=%d Period=%d Width=%d _Delay=%d \r\n", us, Period, Width, _Delay);
}
Last.Reset();
}
// 等待下一次零点,需要考虑继电器动作延迟
bool ACZero::Wait(int usDelay) const
{
if (Count == 0) return false;
// 计算上一次零点后过去的时间
int us = Last.Elapsed();
if (us < 0 && us > 40000) return false;
// 计算下一次零点什么时候到来
us = Period - us;
// 继电器动作延迟
us -= usDelay;
int d = Period;
while (us < 0) us += d;
while (us > d) us -= d;
//debug_printf("ACZero::Wait 周期=%dus 等待=%dus Width=%dms Count=%d Last=%d Now=%d", Period, us, Width, Count, (int)Last, (int)now);
Time.Delay(us);
//debug_printf(" Now2=%d Cost=%d \r\n", (int)Sys.Ms(), us);
return true;
}