按时序执行动作的程序

 使用一个结构体描述执行的动作,使用一个数组组成动作组,通过一个定时器遍历这个动作组。

#include "action.h"
#include "stm32f4xx_hal.h"

#include "switch_control.h"
#include "analog_io.h"
#define MAX_ACTIONS 20  //每组动作最大动作数量
#define ACT_NUM     4   //动作组总数


static Action action_set_1[20];
static Action action_set_2[2];
static Action action_set_3[2];
static Action action_set_4[2];


Action_ctrl act_ctrl_st[ACT_NUM] = {0};
//任务优先级
#define ACTION_TASK_PRIO		10
//任务堆栈大小
#define ACTION_STK_SIZE		500
//任务控制块
OS_TCB ACTION_TaskTCB;
//任务堆栈
CPU_STK ACTION_TASK_STK[ACTION_STK_SIZE];


//以任务形式执行
void start_action_task()
{
    OS_ERR err;
    OSTaskCreate((OS_TCB 	* )&ACTION_TaskTCB,		//任务控制块
                                 (CPU_CHAR	* )"HW_TEST_Task", 		//任务名字
                                 (OS_TASK_PTR )ACTION_TASK, 			//任务函数
                                 (void		* )0,					//传递给任务函数的参数
                                 (OS_PRIO	  )ACTION_TASK_PRIO,     //任务优先级
                                 (CPU_STK   * )&ACTION_TASK_STK[0],	//任务堆栈基地址
                                 (CPU_STK_SIZE)ACTION_STK_SIZE/10,	//任务堆栈深度限位
                                 (CPU_STK_SIZE)ACTION_STK_SIZE,		//任务堆栈大小
                                 (OS_MSG_QTY  )2,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                                 (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                                 (void   	* )0,					//用户补充的存储区
                                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                                 (OS_ERR 	* )&err);
}

void ACTION_TASK(void *pdata)
{
    initialize_actions(); // 初始化动作
    run_actions();
    
}


// 定义计时器相关变量
OS_TMR timer_os_act;        //act定时执行定时器 100ms 0.1s



void Timer_act_Callback(void *p_tmr, void *p_arg)
{
    int i,j,k;

        for(j = 0;j<ACT_NUM;j++)    //动作组编号j
        {
            
            if(act_ctrl_st[j].executed == 1 && act_ctrl_st[j].pause == 0)
            {   
                
                for(i = 0;i < act_ctrl_st[j].action_sum;i++)
                {
                    if(action_set_1[i].start_time == act_ctrl_st[j].time_tick)
                    {
                        execute_action(&action_set_1[i]); // 执行动作
                        
                    }
                }
                act_ctrl_st[j].time_tick++;
            }
            
        }
}

//以定时器形式执行
void start_action_timer(OS_ERR *err)
{
//    OS_ERR err;
    
    
    initialize_actions(); // 初始化动作
        //转阀定时器
    OSTmrCreate(&timer_os_act,
                      "act",
                      1,
                      100/10,
                      OS_OPT_TMR_PERIODIC,
                      (OS_TMR_CALLBACK_PTR)Timer_act_Callback,
                      0,
                      err);
    if(timer_os_act.State != OS_TMR_STATE_RUNNING)
        OSTmrStart(&timer_os_act,err);
    
    
}

//自定义函数

//动作结束函数
static void custom_action_over(int num,float val) {
    act_ctrl_st[num].executed = 0;
    act_ctrl_st[num].time_tick = 0;
    act_ctrl_st[num].stop = 0;
    act_ctrl_st[num].pause = 0;
}


static void custom_action(int num,float val) {
//    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); // 举例:切换某个引脚状态
    ;
}





static void execute_action(Action *action) {
    switch (action->action_type) {
        case SWITCH_ON:
            set_switch_output_state(action->num,1);
            break;
        case SWITCH_OFF:
            set_switch_output_state(action->num,0);
            break;
        case ANALOG_OUTPUT:
            // 模拟量输出逻辑
            Set_DAC_Value(action->num,action->val);
            break;
        case CUSTOM_FUNCTION:
            if (action->func) {
                action->func(action->num,action->val); // 执行自定义函数
            }
            break;
    }
}
//typedef enum {
//    SWITCH_ON,      参数1 操作的开关量编号
//    SWITCH_OFF,     参数1 操作的开关量编号
//    ANALOG_OUTPUT,  参数1 操作的DAC编号,参数2 DAC输出的电压值
//    CUSTOM_FUNCTION 执行自定义函数 参数1 整形  参数2浮点型。
//} ActionType;

//    action_set_1[index++] = (Action){0, SWITCH_ON,        0,      0.0f, NULL         };
//    action_set_1[index++] = (Action){0, SWITCH_OFF,       0,      0.0f, NULL         };
//    action_set_1[index++] = (Action){0, SWITCH_OFF,       0,      0.0f, NULL         };
//    action_set_1[index++] = (Action){0, SWITCH_OFF,       0,      0.0f, NULL         };
//    action_set_1[index++] = (Action){50, SWITCH_OFF,       0,      0.0f, NULL         };
//    //5
//    action_set_1[index++] = (Action){50, SWITCH_OFF,       0,      0.0f, NULL         };
//    action_set_1[index++] = (Action){50, SWITCH_OFF,       0,      0.0f, NULL         };
//    action_set_1[index++] = (Action){50, SWITCH_OFF,       0,      0.0f, NULL         };
//    action_set_1[index++] = (Action){50, SWITCH_OFF,       0,      0.0f, NULL         };
//    action_set_1[index++] = (Action){50, SWITCH_OFF,       0,      0.0f, NULL         };
//    //10

static void initialize_actions() {
    int index = 0;
    // 初始化动作集合           t*100ms 
    /*动作组1*/    
    action_set_1[index++] = (Action){0, SWITCH_ON,        10,      0.0f, NULL         };
    action_set_1[index++] = (Action){0, SWITCH_OFF,       11,      0.0f, NULL         };
    action_set_1[index++] = (Action){0, SWITCH_ON,       12,      0.0f, NULL         };
    action_set_1[index++] = (Action){0, SWITCH_OFF,       13,      0.0f, NULL         };
    action_set_1[index++] = (Action){51, SWITCH_ON,       10,      0.0f, NULL         };
    //5
    action_set_1[index++] = (Action){51, SWITCH_OFF,      11,      0.0f, NULL         };
    action_set_1[index++] = (Action){51, SWITCH_ON,       12,      0.0f, NULL         };
    action_set_1[index++] = (Action){52, SWITCH_OFF,       13,      0.0f, NULL         };
    action_set_1[index++] = (Action){52, SWITCH_ON,       14,      0.0f, NULL         };
    action_set_1[index++] = (Action){52, SWITCH_OFF,       15,      0.0f, NULL         };
    //10
    action_set_1[index++] = (Action){53, SWITCH_OFF,       10,      0.0f, NULL         };
    action_set_1[index++] = (Action){53, SWITCH_ON,       11,      0.0f, NULL         };
    action_set_1[index++] = (Action){54, SWITCH_OFF,       12,      0.0f, NULL         };
    action_set_1[index++] = (Action){54, SWITCH_ON,       13,      0.0f, NULL         };
    action_set_1[index++] = (Action){55, SWITCH_OFF,       10,      0.0f, NULL         };
    //15
    action_set_1[index++] = (Action){55, SWITCH_OFF,       11,      0.0f, NULL         };
    action_set_1[index++] = (Action){56, SWITCH_ON,             12,      0.0f, NULL         };
    //最后一句执行结束函数
    action_set_1[index++] = (Action){56, CUSTOM_FUNCTION,       0,      0.0f, custom_action_over};
    act_ctrl_st[0].action_sum = 18;   //要和实际数量一致,注意动作组数量定义

    
    /*动作组2*/
    action_set_2[0] = (Action){30, ANALOG_OUTPUT,    75,  150.75f, NULL         };
    act_ctrl_st[1].action_sum = 2;
    

    
    /*动作组3*/
    action_set_3[0] = (Action){10, CUSTOM_FUNCTION,  0,      0.0f, custom_action};
    act_ctrl_st[2].action_sum = 2;

    
    /*动作组4*/
    action_set_4[0] = (Action){40, SWITCH_ON,        0,      0.0f, NULL         };
    action_set_4[1] = (Action){70, SWITCH_OFF,       0,      0.0f, NULL         };
    act_ctrl_st[3].action_sum = 2;
    
}

static void run_actions() {

        
    OS_ERR err;
    
    uint32_t time_tick[4] = {0};
    
    int i,j,k;
    while (1) {
        
        for(j = 0;j<ACT_NUM;j++)    //动作组编号j
        if(act_ctrl_st[j].executed == 1 && act_ctrl_st[j].pause == 0)
        for(i = 0;i < act_ctrl_st[j].action_sum;i++)
        {
            if(action_set_1[i].start_time == act_ctrl_st[j].time_tick)
            {
                execute_action(&action_set_1[i]); // 执行动作
                act_ctrl_st[j].time_tick++;
                
            }
        }
        OSTimeDlyHMSM(0, 0, 0, 100,OS_OPT_TIME_HMSM_NON_STRICT,&err); // 每100毫秒遍历一次    
        
//        // 遍历第一个动作集合
//        if(executed[0] == 1 && pause[0] == 0)
//        for (action_index[0] = 0; action_index[0] < action_counts[0]; action_index[0]++) {
//            if (action_set_1[action_index[0]].start_time == time_tick[0]) {
//                execute_action(&action_set_1[action_index[0]]); // 执行动作
//            }
//        }
//        time_tick[0]++;
//        
//        // 遍历第二个动作集合
//        if(executed[1] == 1 && pause[1] == 0)
//        for (action_index[1] = 0; action_index[1] < action_counts[1]; action_index[1]++) {
//            if (action_set_2[action_index[1]].start_time == time_tick[1]) {
//                execute_action(&action_set_2[action_index[1]]); // 执行动作
//            }
//        }
//        time_tick[1]++;
//        
//        // 遍历第三个动作集合
//        if(executed[2] == 1 && pause[2] == 0)
//        for (action_index[2] = 0; action_index[2] < action_counts[2]; action_index[2]++) {
//            if (action_set_3[action_index[2]].start_time == time_tick[2]) {
//                execute_action(&action_set_3[action_index[2]]); // 执行动作
//            }
//        }
//        time_tick[2]++;
//        
//        // 遍历第四个动作集合
//        if(executed[3] == 1 && pause[3] == 0)
//        for (action_index[3] = 0; action_index[3] < action_counts[3]; action_index[3]++) {
//            if (action_set_4[action_index[3]].start_time == time_tick[3]) {
//                execute_action(&action_set_4[action_index[3]]); // 执行动作
//            }
//        }
//        time_tick[3]++;
        
        
    }
}

//void action_start(int action_num)
//{
//    executed[action_num] = 1;
//}

void action_pause(int action_num)
{
    act_ctrl_st[action_num].executed = 1;
    act_ctrl_st[action_num].stop     = 0;
    act_ctrl_st[action_num].pause    = 1;
//    action_index[action_num] = 0;
}
void action_continue(int action_num)
{
    if(act_ctrl_st[action_num].pause == 1)  
    {    
        act_ctrl_st[action_num].executed  = 1;
        act_ctrl_st[action_num].pause     = 0;
        act_ctrl_st[action_num].stop      = 0;
    }
}

void action_stop(int action_num)
{
    act_ctrl_st[action_num].executed  = 0;
    act_ctrl_st[action_num].stop      = 1;
    act_ctrl_st[action_num].pause     = 0;
    act_ctrl_st[action_num].time_tick = 0;  //从头开始
}

void action_executed(int action_num)
{
    act_ctrl_st[action_num].executed  = 1;
    act_ctrl_st[action_num].stop      = 0;
    act_ctrl_st[action_num].pause     = 0;
}

#ifndef ACTION_H
#define ACTION_H

#include <stdint.h>
#include <stdbool.h>
#include "os.h" // uC/OS-III 头文件
typedef enum {
    SWITCH_ON,
    SWITCH_OFF,
    ANALOG_OUTPUT,
    CUSTOM_FUNCTION
} ActionType;

typedef struct Action {
    uint32_t start_time;          // 动作开始执行的时间(以100毫秒为单位)
    ActionType action_type;       // 动作类型
    int num;                      // 动作值1
    float val;                    // 动作值2
    void (*func)(int num,float val);           // 执行函数指针,参数1为动组作编号
} Action;

typedef struct Action_c {
    uint8_t stop;
    uint8_t pause;
    uint8_t executed;
    int action_index;
    int action_sum;
    int time_tick;
} Action_ctrl;

//任务函数
//氢火焰信号测试任务
void ACTION_TASK(void *pdata);


// 函数声明
static void execute_action( Action *action);
static void initialize_actions();
static void run_actions();
static void custom_action(int num,float val);


void start_action_task();

//以定时器形式执行
void start_action_timer(OS_ERR *err);

void action_pause(int action_num);

void action_continue(int action_num);

void action_stop(int action_num);

void action_executed(int action_num);

#endif // ACTION_H

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于使用博图(B&R Automation Studio)制作PLC的时序控制程序,以下是一个简单的示例,展示如何实现一个1200PLC的时序控制程序: 1. 首先,创建一个新的PLC项目,并添加一个主程序块。 2. 定义输入和输出变量,这些变量将用于与外部设备进行通信。例如,可以定义一个输入变量`StartButton`来接收启动信号,一个输出变量`Motor`用于控制电机运行。 3. 在主程序块中,使用Step块和Timer块来实现时序控制逻辑。以下是一个示例的程序代码: ```plc VAR StartButton: BOOL; (* 输入变量:启动按钮 *) Motor: BOOL; (* 输出变量:电机控制信号 *) Timer: TON; (* 定时器 *) END_VAR IF StartButton THEN Timer(IN:=TRUE, PT:=T#1s); (* 启动定时器,1秒延迟 *) IF Timer.Q THEN Motor := TRUE; (* 定时器达到设定时间后,开启电机 *) END_IF ELSE Timer(IN:=FALSE); (* 停止定时器 *) Motor := FALSE; (* 关闭电机 *) END_IF ``` 在上述示例中,当`StartButton`被触发时,定时器`Timer`开始计时,并在1秒后输出信号`Motor`来控制电机运行。如果`StartButton`被释放或按下之前定时器时间到达,定时器将停止,并且电机将被关闭。 请注意,以上仅仅是一个简单的示例,实际的时序控制程序可能涉及更多的输入输出变量、逻辑条件和动作。在实际应用中,您需要根据具体的控制需求进行适当的修改和扩展。另外,在使用博图进行PLC编程时,请参考博图的相关文档和教程,以确保按照正确的语法和规范进行编程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值