#include "apdefap.h"
int gscAction( void )
{
//==================== 【公共临时局部变量定义区】====================
//系统时间相关变量,用于获取本地时分秒、换算当日总分钟做定时判断
struct tm* pLocalTime; //系统时间结构体指针,存放解析后的时/分/秒/日/月/年
time_t lTime; //时间戳变量,存储从1970至今的秒数原始时间
int CurHour; //提取当前系统小时,范围0~23
int CurMin; //提取当前系统分钟,范围0~59
int CurSec; //提取当前系统秒,仅用于计时累加,定时判断不使用
int CurTotalMin; //当日总分钟 = 小时*60+分钟,统一换算后简化定时区间对比逻辑
//模式控制、计时相关变量
unsigned long AltEn; //整机模式总开关变量,DWord类型:0关闭/1手动/2时长轮换/4时控轮换
unsigned long SetMin; //模式2专用:单台风机设定运行时长,单位分钟
unsigned long Min_Cnt; //全局运行累计分钟计时器,所有运行模式共用
unsigned long Sec_Cnt; //全局运行累计秒计时器,所有运行模式共用
unsigned long RunFlag; //当前运行风机标记:0无风机运行/1风机1运行/2风机2运行
unsigned long C_HHMM;
unsigned long C_StartHHMM,C_SotopHHMM;
static BOOL TimerSwitchBit; //模式4专用切换位BOOL变量,0启动风机1,1启动风机2,定时有效边沿自动取反
static BOOL TimerSwitchBitp; //模式4专用切换位BOOL变量,0启动风机1,1启动风机2,定时有效边沿自动取反
BOOL bAnyMotorRun; //公共判断标记:任意一台风机输出启动信号则置1,用于统一计时逻辑
//PLC侧风机硬件状态反馈点位
BOOL bM1Remote; //风机1远程自动模式反馈,等于3代表切本地手动,需整机停机保护
BOOL bM1Fault; //风机1故障报警信号,1=故障,0=正常
BOOL bM2Remote; //风机2远程自动模式反馈,等于3代表切本地手动,需整机停机保护
BOOL bM2Fault; //风机2故障报警信号,1=故障,0=正常
//画面手动操作按钮变量,模式1手动模式使用
BOOL bManualM1Start; //画面手动启动风机1按钮,1=按下启动,0=松开停止
BOOL bManualM2Start; //画面手动启动风机2按钮,1=按下启动,0=松开停止
//模式4时控专用标记
BOOL bTimerValid = 0; //定时总有效标记,初始0;M1任意一组启用定时在当前时间区间内置1
int i; //定时循环遍历索引,循环0~19,遍历20组定时参数
//==================== 【第一步:统一读取系统本地时间】====================
lTime = time(NULL); //获取当前系统时间戳,返回秒数存入lTime
pLocalTime = localtime(&lTime); //将时间戳转换为本地时区可读时间结构体
CurHour = pLocalTime->tm_hour; //从结构体取出当前小时赋值给CurHour
CurMin = pLocalTime->tm_min; //从结构体取出当前分钟赋值给CurMin
CurSec = pLocalTime->tm_sec; //从结构体取出当前秒赋值给CurSec
CurTotalMin = CurHour * 60 + CurMin;//换算当前时间为当日总分钟,用于定时区间对比
C_HHMM = CurHour*100 + CurMin ;
//==================== 【第二步:一次性读取全部外部标签变量】====================
AltEn = GetTagDWord("Alt_Enable"); //读取整机模式总开关DWord变量
SetMin = GetTagDWord("Run_Time_Min"); //读取模式2单台风机设定运行分钟
Min_Cnt = GetTagDWord("Min_Cnt"); //读取全局累计分钟计时器当前值
Sec_Cnt = GetTagDWord("Sec_Cnt"); //读取全局累计秒计时器当前值
RunFlag = GetTagDWord("Run_Motor_Flag"); //读取当前运行风机标记
//TimerSwitchBit = GetTagBit("Timer_Switch_Cnt"); //读取模式4风机切换BOOL位
bManualM1Start = GetTagBit("Manual_M1_Start"); //读取画面手动风机1启动按钮状态
bManualM2Start = GetTagBit("Manual_M2_Start"); //读取画面手动风机2启动按钮状态
bM1Remote = GetTagBit("LCFJ1.Remote"); //读取风机1远程/本地模式反馈
bM1Fault = GetTagBit("LCFJ1.Fault"); //读取风机1故障信号
bM2Remote = GetTagBit("LCFJ2.Remote"); //读取风机2远程/本地模式反馈
bM2Fault = GetTagBit("LCFJ2.Fault"); //读取风机2故障信号
C_StartHHMM = GetTagDWord("Sk_StartHm"); //读取当前运行风机标记
C_SotopHHMM = GetTagDWord("Sk_SotopHm"); //读取当前运行风机标记
//==================== 【最高优先级保护逻辑1:两台风机同时故障,整机强制停机清零】====================
if(bM1Fault == 1 && bM2Fault == 1) //判断风机1、风机2同时存在故障报警
{
SetTagBit("LCFJ1.Start_Button", 0); //输出风机1启动信号置0,停止风机1
SetTagBit("LCFJ1.Stop_Button", 1); //输出风机1停止信号置1,强制停机
SetTagBit("LCFJ2.Start_Button", 0); //输出风机2启动信号置0,停止风机2
SetTagBit("LCFJ2.Stop_Button", 1); //输出风机2停止信号置1,强制停机
SetTagDWord("Min_Cnt", 0); //运行分钟计时器清零
SetTagDWord("Sec_Cnt", 0); //运行秒计时器清零
SetTagDWord("Run_Motor_Flag", 0); //运行风机标记置0,无风机运行
SetTagBit("Timer_Switch_Cnt", 0); //模式4风机切换位复位初始0
//SetTagDWord("Alt_Enable", 0); //
return 0; //保护触发,直接结束本次动作循环,不再执行后续逻辑
}
//==================== 【最高优先级保护逻辑2:任意风机切本地非远程模式,整机停机清零】====================
if(bM1Remote == 0 || bM2Remote == 0) //风机1或风机2本地模式反馈等于3,退出自动控制
{
SetTagBit("LCFJ1.Start_Button", 0); //风机1启动输出关闭
SetTagBit("LCFJ1.Stop_Button", 1); //风机1停止输出打开
SetTagBit("LCFJ2.Start_Button", 0); //风机2启动输出关闭
SetTagBit("LCFJ2.Stop_Button", 1); //风机2停止输出打开
SetTagDWord("Min_Cnt", 0); //分钟计时清零
SetTagDWord("Sec_Cnt", 0); //秒计时清零
SetTagDWord("Run_Motor_Flag", 0); //运行标记清零
SetTagBit("Timer_Switch_Cnt", 0); //时控切换位复位
return 0; //保护触发,直接退出本次循环
}
//==================== 【模式4专用:遍历20组定时,判断当前时间是否在定时区间内】====================
bTimerValid = 0; //定时有效标记先初始化为0,默认定时未激活
for(i = 0; i < 1; i++) //循环i从0到19,遍历全部20组M1定时参数
{
char szEn[30]; //字符缓冲区,拼接每组定时启用变量名,长度30足够存储
char szStart[30]; //字符缓冲区,拼接每组定时启动时间变量名
char szStop[30]; //字符缓冲区,拼接每组定时停止时间变量名
int En; //本组定时启用状态:1启用,0禁用
int StartHHMM; //本组启动时间合并数字,格式HHMM,例0830=8点30分
int StopHHMM; //本组停止时间合并数字,格式HHMM,例2300=23点整
int S_H, S_M; //拆分后启动小时、启动分钟
int E_H, E_M; //拆分后停止小时、停止分钟
int StartMin; //本组启动时间换算当日总分钟
int EndMin; //本组停止时间换算当日总分钟
sprintf(szEn, "M1_En%d", i); //拼接变量名:M1_En0、M1_En1...M1_En19
sprintf(szStart, "M1_Start_T%d", i); //拼接变量名:M1_Start_T0~M1_Start_T19
sprintf(szStop, "M1_Stop_T%d", i); //拼接变量名:M1_Stop_T0~M1_Stop_T19
// En = GetTagDWord(szEn); //读取当前组定时启用状态
En = 1; //读取当前组定时启用状态
if(En != 1) continue; //本组定时未启用,跳过本组,判断下一组定时
// StartHHMM = GetTagDWord(szStart); //读取本组启动HHMM时间数值
// StopHHMM = GetTagDWord(szStop); //读取本组停止HHMM时间数值
StartHHMM = C_StartHHMM; //读取本组启动HHMM时间数值
StopHHMM = C_SotopHHMM; //读取本组停止HHMM时间数值
S_H = StartHHMM / 100; //整除100拆分出启动小时
S_M = StartHHMM % 100; //对100取余拆分出启动分钟
E_H = StopHHMM / 100; //整除100拆分出停止小时
E_M = StopHHMM % 100; //对100取余拆分出停止分钟
StartMin = S_H * 60 + S_M; //启动时间换算当日总分钟
EndMin = E_H * 60 + E_M; //停止时间换算当日总分钟
if(StartMin <= EndMin) //定时区间不跨零点,如0800~1800,当天内区间
{
if(CurTotalMin >= StartMin && CurTotalMin < EndMin) //当前时间落在定时区间内
{
bTimerValid = 1; //置定时总有效标记为1
break; //找到有效定时组,跳出循环无需判断剩余定时
}
}
else //定时跨零点场景,如2330~0120,跨次日凌晨
{
if(CurTotalMin >= StartMin || CurTotalMin < EndMin) //当前时间在跨天区间内
{
bTimerValid = 1; //置定时总有效标记为1
break; //找到有效定时,直接跳出循环
}
}
}
//==================== 【模式分支选择器:根据AltEn切换对应控制逻辑】====================
switch(AltEn) //依据整机模式开关值,进入对应功能分支
{
//==================== Case0:模式0,整机关闭,全部风机停机、所有标记清零 ====================
case 1:
{
SetTagBit("LCFJ1.Start_Button", 0); //风机1启动输出关闭
SetTagBit("LCFJ1.Stop_Button", 1); //风机1停止输出打开
SetTagBit("LCFJ2.Start_Button", 0); //风机2启动输出关闭
SetTagBit("LCFJ2.Stop_Button", 1); //风机2停止输出打开
SetTagDWord("Min_Cnt", 0); //运行分钟计时清零
SetTagDWord("Sec_Cnt", 0); //运行秒计时清零
SetTagDWord("Run_Motor_Flag", 0); //运行风机标记清零
// SetTagBit("Timer_Switch_Cnt", 0); //时控模式切换位复位0
RunFlag = 0;
TimerSwitchBitp=0;
SetTagBit("Manual_M1_Start",0); //切换至手动模式,复位风机1手动启动按钮锁存
SetTagBit("Manual_M2_Start",0); //切换至手动模式,复位风机2手动启动按钮锁存
break; //退出case0分支,执行后续统一计时逻辑
}
//==================== Case1:模式1,手动模式,画面按钮独立控制两台风机 ====================
case 2:
{
//SetTagBit("Manual_M1_Start",0); //切换至手动模式,复位风机1手动启动按钮锁存
//SetTagBit("Manual_M2_Start",0); //切换至手动模式,复位风机2手动启动按钮锁存
SetTagBit("Timer_Switch_Cnt", 0); //切换手动,复位时控专用切换位
TimerSwitchBitp=0;
//----------------------风机1手动启停控制逻辑----------------------
if(bManualM1Start == 1) //画面手动启动风机1按钮按下
{
SetTagBit("LCFJ1.Start_Button", 1); //风机1启动输出置1,启动风机
SetTagBit("LCFJ1.Stop_Button", 0); //风机1停止输出置0,解除停机指令
if(RunFlag != 1) //当前运行标记不是风机1,代表刚切换启动风机1
{
Min_Cnt = 0; //切换风机时计时清零
Sec_Cnt = 0;
RunFlag = 1; //更新运行标记为风机1
}
}
else //手动按钮松开,停止风机1
{
SetTagBit("LCFJ1.Start_Button", 0); //关闭风机1启动输出
SetTagBit("LCFJ1.Stop_Button", 1); //打开风机1停止输出
}
//----------------------风机2手动启停控制逻辑----------------------
if(bManualM2Start == 1) //画面手动启动风机2按钮按下
{
SetTagBit("LCFJ2.Start_Button", 1); //风机2启动输出置1,启动风机
SetTagBit("LCFJ2.Stop_Button", 0); //风机2停止输出置0,解除停机指令
if(RunFlag != 2) //当前运行标记不是风机2,刚切换启动风机2
{
Min_Cnt = 0; //切换风机计时清零
Sec_Cnt = 0;
RunFlag = 2; //更新运行标记为风机2
}
}
else //手动按钮松开,停止风机2
{
SetTagBit("LCFJ2.Start_Button", 0); //关闭风机2启动输出
SetTagBit("LCFJ2.Stop_Button", 1); //打开风机2停止输出
}
if((bManualM2Start == 0) && (bManualM1Start == 0))
{
RunFlag = 0;
Min_Cnt = 0; //切换风机计时清零
Sec_Cnt = 0;
}
break; //退出case1手动分支,执行统一计时逻辑
}
//==================== Case2:模式2,时长自动轮换模式,两台风机互斥定时切换 ====================
case 3:
{
SetTagBit("Manual_M1_Start",0); //进入轮换模式,复位手动风机1按钮
SetTagBit("Manual_M2_Start",0); //进入轮换模式,复位手动风机2按钮
SetTagBit("Timer_Switch_Cnt", 0); //切换轮换模式,复位时控切换位
TimerSwitchBitp=0;
if (RunFlag == 0) //无风机运行,初始化默认启动风机2
{
RunFlag = 2; //运行标记设为风机2
Min_Cnt = 0; //计时清零
Sec_Cnt = 0;
}
//----------------------风机运行故障自动切换逻辑----------------------
if(RunFlag == 1 && bM1Fault == 1) //当前运行风机1且风机1故障
{
RunFlag = 2; //切换运行风机2
Min_Cnt = 0; //切换风机计时清零
Sec_Cnt = 0;
}
if(RunFlag == 2 && bM2Fault == 1) //当前运行风机2且风机2故障
{
RunFlag = 1; //切换运行风机1
Min_Cnt = 0; //切换风机计时清零
Sec_Cnt = 0;
}
//----------------------互斥输出风机启停信号 + 时长到达切换逻辑----------------------
if(RunFlag == 1) //标记为风机1运行
{
SetTagBit("LCFJ1.Start_Button", 1); //风机1启动输出打开
SetTagBit("LCFJ1.Stop_Button", 0); //风机1停止输出关闭
SetTagBit("LCFJ2.Start_Button", 0); //风机2启动输出关闭
SetTagBit("LCFJ2.Stop_Button", 1); //风机2停止输出打开
if(Min_Cnt >= SetMin) //累计运行分钟达到设定轮换时长
{
RunFlag = 2; //切换运行风机2
Min_Cnt = 0; //新风机启动计时清零
Sec_Cnt = 0;
}
}
else if(RunFlag == 2) //标记为风机2运行
{
SetTagBit("LCFJ1.Start_Button", 0); //风机1启动输出关闭
SetTagBit("LCFJ1.Stop_Button", 1); //风机1停止输出打开
SetTagBit("LCFJ2.Start_Button", 1); //风机2启动输出打开
SetTagBit("LCFJ2.Stop_Button", 0); //风机2停止输出关闭
if(Min_Cnt >= SetMin) //累计运行分钟达到设定轮换时长
{
RunFlag = 1; //切换运行风机1
Min_Cnt = 0; //新风机启动计时清零
Sec_Cnt = 0;
}
}
break; //退出case2轮换分支,执行统一计时逻辑
}
//==================== Case4:模式4,时控轮换模式,定时有效交替运行风机1/2 ====================
case 4:
{
SetTagBit("Manual_M1_Start",0); //进入时控轮换,复位手动风机1按钮
SetTagBit("Manual_M2_Start",0); //进入时控轮换,复位手动风机2按钮
if(bTimerValid == 0) //当前时间不在定时区间内,定时失效
{
SetTagBit("LCFJ1.Start_Button", 0); //风机1启动输出关闭
SetTagBit("LCFJ1.Stop_Button", 1); //风机1停止输出打开
SetTagBit("LCFJ2.Start_Button", 0); //风机2启动输出关闭
SetTagBit("LCFJ2.Stop_Button", 1); //风机2停止输出打开
SetTagDWord("Run_Motor_Flag", 0); //运行标记清零
TimerSwitchBitp =0;
RunFlag = 0;
break; //定时失效,退出case4分支,执行计时逻辑
}
//if(RunFlag == 0) //定时刚从失效变为有效,首次触发,切换风机顺序
//{
// TimerSwitchBit = !TimerSwitchBit; //BOOL切换位取反,0变1、1变0
// SetTagBit("Timer_Switch_Cnt", TimerSwitchBit); //回写切换位变量
//// Min_Cnt = 0; //定时重新触发,计时清零
// Sec_Cnt = 0;
// if(TimerSwitchBit == 0) //切换位为0,本次启动风机1
// RunFlag = 1;
// else //切换位为1,本次启动风机2
// RunFlag = 2;
//}
if(TimerSwitchBitp == 0)
{
TimerSwitchBitp =1;
TimerSwitchBit=!TimerSwitchBit;
//SetTagBit("Timer_Switch_Cnt", TimerSwitchBit); //回写切换位变量
Min_Cnt = 0; //定时重新触发,计时清零
Sec_Cnt = 0;
if(TimerSwitchBit == 0) //切换位为0,本次启动风机1
RunFlag = 1;
else //切换位为1,本次启动风机2
RunFlag = 2;
}
//----------------------时控运行中风机故障自动切换----------------------
if(RunFlag == 1 && bM1Fault == 1) //当前运行风机1故障
{
RunFlag = 2; //切换风机2运行
Min_Cnt = 0; //故障切换计时清零
Sec_Cnt = 0;
}
if(RunFlag == 2 && bM2Fault == 1) //当前运行风机2故障
{
RunFlag = 1; //切换风机1运行
Min_Cnt = 0; //故障切换计时清零
Sec_Cnt = 0;
}
//----------------------时控互斥输出风机启停信号----------------------
if(RunFlag == 1) //标记风机1运行
{
SetTagBit("LCFJ1.Start_Button", 1); //风机1启动打开
SetTagBit("LCFJ1.Stop_Button", 0); //风机1停止关闭
SetTagBit("LCFJ2.Start_Button", 0); //风机2启动关闭
SetTagBit("LCFJ2.Stop_Button", 1); //风机2停止打开
}
else if(RunFlag == 2) //标记风机2运行
{
SetTagBit("LCFJ1.Start_Button", 0); //风机1启动关闭
SetTagBit("LCFJ1.Stop_Button", 1); //风机1停止打开
SetTagBit("LCFJ2.Start_Button", 1); //风机2启动打开
SetTagBit("LCFJ2.Stop_Button", 0); //风机2停止关闭
}
break; //退出case4时控分支,执行统一计时逻辑
}
}
//==================== 【全模式统一计时逻辑:任意风机运行则累加时分,无运行清零】====================
// bAnyMotorRun = (GetTagBit("LCFJ1.Start_Button") || GetTagBit("LCFJ2.Start_Button"));
bAnyMotorRun = RunFlag;
//读取最终输出启动点位,两台任意一台输出1,标记bAnyMotorRun置1
if(bAnyMotorRun > 0) //存在风机正在运行
{
Sec_Cnt = Sec_Cnt + 1; //运行秒计数器+1,每秒动作触发一次则秒+1
if(Sec_Cnt >= 60) //秒计数达到60秒,进位分钟
{
Sec_Cnt = 0; //秒计数器归零
Min_Cnt = Min_Cnt + 1; //分钟计数器+1
}
}
else //无任何风机输出运行信号
{
Min_Cnt = 0; //分钟计时清零
Sec_Cnt = 0; //秒计时清零
RunFlag = 0; //运行风机标记清零,代表无风机运行
}
//==================== 回写更新所有计时、运行标记外部变量 ====================
SetTagDWord("Min_Cnt", Min_Cnt); //回写累计分钟计时器
SetTagDWord("Sec_Cnt", Sec_Cnt); //回写累计秒计时器
SetTagDWord("Run_Motor_Flag", RunFlag); //回写当前运行风机标记
SetTagDWord("SyHHMM", C_HHMM); //回写当前运行风机标记
return 0; //全局动作正常执行完毕,返回0标准结束值
}