📄 simpleplcfunc.c
字号:
/*
简易PLC功能
作者:吴健
编写日期:2008年1月2日-1月3日
版本:1.0 测试完成
软件支持:输入触点、输出继电器、中间继电器,定时器、计数器
*/
#include <avr\io.h>
#include "SimplePLC.h"
// 时间变量
struct STime{
unsigned char count; // 多少个0.01秒
unsigned char second; // 秒
unsigned char minute; // 分钟
unsigned char hour; // 小时
unsigned char day ; // 日期
unsigned char month; // 月份
unsigned char year; // 年
}now,Timer[MAX_TIMER]; // 当前时间、MAX_TIMER组定时器
unsigned char TimerMutex[MAX_TIMER]; // MAX_TIMER组定时器的运行信号
unsigned char TimerAddMutex[MAX_TIMER]; // MAX_TIMER组增加定时器时间的运行信号
unsigned char TimerSubMutex[MAX_TIMER]; // MAX_TIMER组减少定时器时间的运行信号
unsigned char year_err = 0; // 年份减法出错位,0:正常,1:出错
unsigned int INPORT=0,OUTPORT=0; // 虚拟输入输出端口,各16个节点
unsigned char tmpPORT[MAX_TMPPORT]; // 暂存的变量
unsigned char cur_tmp_p = 0; // 当前的暂存变量
unsigned int APORT[MAX_APUT]; // 中间触点
unsigned int stack_op[STACK_MAX]; // 堆栈
signed char stack_p=-1; // 堆栈指针
unsigned char stack_err = 0; // 堆栈错误
// 计数器变量
#ifdef _PLC_USE_C_
unsigned int Counter[MAX_COUNTER]; // 最大计数长度65535
unsigned char CounterOut[MAX_COUNTER]; // 计数器计数到达后的输出状态,0表示未到达,1表示到达
unsigned char CounterNowValue[MAX_COUNTER]; // 计数器当前值
#endif
// 定时器0的溢出中断
SIGNAL(SIG_OVERFLOW0)
{
now.count++;
if(now.count == 99)
{
now.second++;
now.count = 0;
}
TCNT0 = 256 - 0.01/(1024.0/F_CPU);
sei();
}
// 堆栈处理函数
// 数据压栈
void push_stack(unsigned int dat)
{
if(stack_p < STACK_MAX)
{
stack_p++;
stack_op[stack_p] = dat;
}
}
// 数据出栈
unsigned int pop_stack(void)
{
unsigned int tmp;
if(stack_p > -1)
{
tmp = stack_op[stack_p];
stack_p--;
stack_err = 0;
return tmp;
}
stack_err = 1; // 堆栈错误
return 0;
}
// 清除堆栈中所有的元素
void clear_stack(void)
{
stack_p = -1;
stack_err = 0;
}
// 得到栈顶的元素
unsigned int gettop_stack(void)
{
if(stack_p > -1)
{
stack_err = 0;
return stack_op[stack_p];
}else{
stack_err = 1;
return 0;
}
}
void PUSH_STACK()
{
push_stack(tmpPORT[cur_tmp_p]); // 压栈命令
}
// 动作
// 取常开输入输出和中间触点
void LD(unsigned char a)
{
unsigned char tmp = tmpPORT[cur_tmp_p];
wdt_reset(); // 喂狗,表示程序在正常运行
if(a<MAX_INPUT) // 输入触点
{
if(Get_Bit(INPORT,a))
tmp = tmp & 1;
else
tmp = 0;
}else if(a<OUTPUT_TOP){ // 输出触点
a = a - MAX_INPUT;
if(Get_Bit(OUTPORT,a))
tmp = tmp & 1;
else
tmp = 0;
}else if(a<APUT_TOP){ // 中间触点
a -= OUTPUT_TOP;
if(APORT[a])
tmp = tmp & 1;
else
tmp = 0;
}else{ // 计数器触点
a -= APUT_TOP;
if(CounterOut[a])
tmp = tmp & 1;
else
tmp = 0;
}
tmpPORT[cur_tmp_p] = tmp;
}
// 取常闭输入输出和中间触点
void NLD(unsigned char a)
{
unsigned char tmp = tmpPORT[cur_tmp_p];
wdt_reset(); // 喂狗,表示程序在正常运行
if(a<MAX_INPUT) // 输入触点
{
if(Get_Bit(INPORT,a)>>a)
tmp = 0;
else
tmp = tmp & 1;
}else if(a<OUTPUT_TOP){ // 输出触点
a = a - MAX_INPUT;
if(Get_Bit(OUTPORT,a)>>a)
tmp = 0;
else
tmp = tmp& 1;
}else if(a<APUT_TOP){ // 中间触点
a = a - OUTPUT_TOP;
if(APORT[a])
tmp = 0;
else
tmp = tmp & 1;
}else{ // 计数器触点
a -= APUT_TOP;
if(CounterOut[a])
tmp = 0;
else
tmp = tmp & 1;
}
tmpPORT[cur_tmp_p] = tmp;
}
// 初始化取触点
void ST(unsigned char a)
{
unsigned char tmp = tmpPORT[cur_tmp_p];
clear_stack();
wdt_reset(); // 喂狗,表示程序在正常运行
if(a<MAX_INPUT) // 输入触点
{
if(Get_Bit(INPORT,a))
tmp = 1;
else
tmp = 0;
}else if(a<OUTPUT_TOP){ // 输出触点
a = a - MAX_INPUT;
if(Get_Bit(OUTPORT,a))
tmp = 1;
else
tmp = 0;
}else if(a<APUT_TOP){ // 中间触点
a = a - OUTPUT_TOP;
if(APORT[a])
tmp = 1;
else
tmp = 0;
}else{ // 计数器触点
a -= APUT_TOP;
if(CounterOut[a])
tmp = 1;
else
tmp = 0;
}
tmpPORT[cur_tmp_p] = tmp;
}
// 常开逻辑与输入输出和中间触点
void AND(unsigned char a)
{
unsigned char tmp = tmpPORT[cur_tmp_p];
if(a < MAX_INPUT)
{
if(Get_Bit(INPORT,a))
tmp = tmp & 1;
else
tmp = 0;
}else if(a<OUTPUT_TOP){
a = a - MAX_INPUT;
if(Get_Bit(OUTPORT,a))
tmp = tmp & 1;
else
tmp = 0;
}else if(a<APUT_TOP){ // 中间触点
a = a - OUTPUT_TOP;
if(APORT[a])
tmp = tmp & 1;
else
tmp = 0;
}else{ // 计数器触点
a -= APUT_TOP;
if(CounterOut[a])
tmp = tmp & 1;
else
tmp = 0;
}
tmpPORT[cur_tmp_p] = tmp;
}
// 常闭逻辑与输入触点
void NAND(unsigned char a)
{
unsigned char tmp = tmpPORT[cur_tmp_p];
if(a < MAX_INPUT)
{
if(Get_Bit(INPORT,a))
tmp = 0;
else
tmp = tmp & 1;
}else if(a<OUTPUT_TOP){
a = a - MAX_INPUT;
if(Get_Bit(OUTPORT,a))
tmp = 0;
else
tmp = tmp & 1;
}else if(a<APUT_TOP){ // 中间触点
a = a - OUTPUT_TOP;
if(APORT[a])
tmp = 0;
else
tmp = tmp & 1;
}else{ // 计数器触点
a -= APUT_TOP;
if(CounterOut[a])
tmp = 0;
else
tmp = tmp & 1;
}
tmpPORT[cur_tmp_p] = tmp;
}
// 并联常开输入输出和中间触点
void OR(unsigned char a)
{
unsigned int tmp;
unsigned char tmpPORT1;
tmpPORT1 = tmpPORT[cur_tmp_p];
tmp = gettop_stack();
if(stack_err == 1)
tmp = 1;
if(a < MAX_INPUT)
{
if(Get_Bit(INPORT,a))
tmpPORT1 = (tmp & 1)|tmpPORT1;
else
tmpPORT1 = (0)|tmpPORT1;
}else if(a<OUTPUT_TOP){
a = a - MAX_INPUT;
if(Get_Bit(OUTPORT,a))
tmpPORT1 = (tmp & 1)|tmpPORT1;
else
tmpPORT1 = (0)|tmpPORT1;
}else if(a<APUT_TOP){
a = a - OUTPUT_TOP;
if(APORT[a])
tmpPORT1 = (tmp & 1)|tmpPORT1;
else
tmpPORT1 = (0)|tmpPORT1;
}else{
a -= APUT_TOP;
if(CounterOut[a])
tmpPORT1 = (tmp &1)|tmpPORT1;
else
tmpPORT1 = 0|tmpPORT1;
}
tmpPORT[cur_tmp_p] = tmpPORT1;
}
// 并联常闭输入输出和中间触点
void NOR(unsigned char a)
{
unsigned int tmp;
unsigned char tmpPORT1;
tmpPORT1 = tmpPORT[cur_tmp_p];
tmp = gettop_stack();
if(stack_err == 1)
tmp = 1;
if(a < MAX_INPUT)
{
if(Get_Bit(INPORT,a))
tmpPORT1 = (0)|tmpPORT1;
else
tmpPORT1 = (tmp & 1)|tmpPORT1;
}else if(a<OUTPUT_TOP){
a = a - MAX_INPUT;
if(Get_Bit(OUTPORT,a))
tmpPORT1 = (0)|tmpPORT1;
else
tmpPORT1 = (tmp & 1)|tmpPORT1;
}else if(a<APUT_TOP){
a = a - OUTPUT_TOP;
if(APORT[a])
tmpPORT1 = (0)|tmpPORT1;
else
tmpPORT1 = (tmp & 1)|tmpPORT1;
}else{
a -= APUT_TOP;
if(CounterOut[a])
tmpPORT1 = 0|tmpPORT1;
else
tmpPORT1 = (tmp &1)|tmpPORT1;
}
tmpPORT[cur_tmp_p] = tmpPORT1;
}
// 得到堆栈的最顶部元素,并切换到下一路电路
void GETNEXT(void)
{
unsigned char tmp;
tmp = gettop_stack();
if(cur_tmp_p<MAX_TMPPORT)
{
cur_tmp_p++;
tmpPORT[cur_tmp_p] = tmp;
}
}
// 以或的方式合并所有的电路
void TOTAL(void)
{
unsigned char tmp=tmpPORT[0];
unsigned char i;
for(i=1;i<=cur_tmp_p;i++)
{
tmp = tmp | tmpPORT[i];
}
tmpPORT[0] = tmp;
cur_tmp_p = 0;
}
// 输出输出和中间触点
void OUT(unsigned char a)
{
unsigned char tmpPORT1;
wdt_reset(); // 喂狗,表示程序在正常运行
tmpPORT1 = tmpPORT[cur_tmp_p];
if((a>(MAX_INPUT-1))&&(a<OUTPUT_TOP)) // 输出触点
{
a = a - MAX_INPUT;
if(tmpPORT1)
Set_Bit(OUTPORT,a);
else
Clr_Bit(OUTPORT,a);
}else if((a>=OUTPUT_TOP)&&(a<APUT_TOP)){ // 中间触点
a = a - OUTPUT_TOP;
if(tmpPORT1)
APORT[a] = 1;
else
APORT[a] = 0;
}
}
// 程序刷新输出继电器
void END(void)
{
wdt_reset(); // 喂狗,表示程序在正常运行
PORTC = OUTPORT&0xff;
PORTD = (OUTPORT>>8)&0xff;
}
// 程序刷新输入继电器
void BEG(void)
{
INPORT = PINA+(PINB<<8);
cur_tmp_p = 0; // 当前暂存变量序号
year_err = 0; // 清年份出错位
clear_stack();
AutoTime();
}
// 初始化定时器
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -