微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 结项 全编程高速自动控制系统

结项 全编程高速自动控制系统

时间:10-02 整理:3721RD 点击:

项目描述:
用户可根据不同加工产品或控制需求,通过人机界面间单直观的输入操作自主编写加工或动作程序 。在用户所编程序中自动编写各个输出点、输入触点检测,动作时间延时等,而且所编写的程序都可以多次保存、修改。同时支持自动加工(动作)流程程序,且每条自动加工程序可以任意修改保存,提高现场编程时间,大大提高了工作效率,减轻操作者的劳动强度。全功能开放式设计,用户可根据实际机械结构要求和平时操作习惯,来设定最合适的参数,不用更改芯片或程序,为用户获得宝贵试机和开发时间。

项目需求:
归结为数字端口的输出与输入,延时,流程的编写,涉及到流程的编写首当,应该就是UML流程图。很多的动作流程都是通过流程图进行整理动作流程。
以一个小项目为例:
电动卷闸


关门的流程图所下:


结论:
由流程图看出,可以归结为节点与线,其中线只是表示节点的流向,那么关键就在于节点的表示,以及节点的转换。
节点种类有 椭圆(开始、结束)、菱形(判断)、长方形(动作)

  1. typedef enum flow_mode_typedef {
  2.     Value_Flow_Start,//延时 开始 结束
  3.     Value_Flow_Work,//动作  
  4.     Value_Flow_Judge,//判断
  5.         Value_Flow_Delay,//延时
  6. }flow_mode_e;

复制代码

对流入 流出分析
开始  0入1出
结束  1入0出
动作  1入1出
判断  1入2出 (可能有人疑问不是1入3出,其实其相当于if,最多也只能是1入2出)
其实上面还隐含一个关系, 就是从程序的过程角度出法,其实 开始与结束是结合在一起的。
结束 的一个动作就是开始。
开始的数据结构

  1. typedef struct flow_start_typedef{
  2.     uint8_t     ucR_Num;//序列号
  3.     flow_mode_e eR_Mode;
  4.     uint8_t     ucR_NumNext;
  5.     uint32_t    ul_DelayMs;
  6. }flow_start_t;

复制代码


动作的数据结构

  1. typedef struct flow_work_typedef{
  2.     uint8_t     ucR_Num;//序列号
  3.     flow_mode_e eR_Mode;
  4.     uint8_t     ucR_NumNext;
  5.     output_t    ucR_OutPutNum;
  6.     uint8_t     ucR_OutPutData;
  7.     //void (* funP_Word)(output_t );  //Value_Flow_Start Value_Flow_Work
  8. }flow_work_t;

复制代码

判断的数据结束

  1. typedef struct flow_judge_typedef{
  2.     uint8_t     ucR_Num;//序列号
  3.     flow_mode_e eR_Mode;
  4.     uint8_t     ucR_NumNext;//正确的出口
  5.     uint8_t     ucR_NumFalseNext;//错误的出口
  6.     input_t     ucR_InPutNum;
  7.     //bool (* funP_Judge)(input_t );
  8. }flow_judge_t;

复制代码


但是再从编写的角度,归结到一类的写法就不方便。所以最后,结束在一起。如下所示:

  1. typedef enum flow_mode_typedef {
  2.     Value_Flow_Start,//延时 开始 结束
  3.     Value_Flow_Work,//动作  
  4.     Value_Flow_Judge,//判断
  5.         Value_Flow_Delay,//延时
  6. }flow_mode_e;

  7. typedef uint8_t output_t;
  8. typedef uint8_t input_t;


  9. typedef struct flow_typedef{
  10.     uint8_t     ucR_Num;//序列号
  11.     flow_mode_e eR_Mode;
  12.     uint8_t     ucR_NumNext;
  13.    
  14.     uint32_t    ul_DelayMs;
  15.    
  16.     output_t    ucR_OutPutNum;
  17.     uint8_t     ucR_OutPutData;
  18.    
  19.     uint8_t     ucR_NumFalseNext;//错误的出口
  20.     input_t     ucR_InPutNum;
  21. }flow_t;

复制代码

程序

  1. flow_t * S_Log_Flow_Found(uint8_t ucR_Num)
  2. {
  3.     uint8_t i = 0;
  4.     for(i=0;i<Value_ArraryFlowNum;i++)
  5.     {
  6.         if(stA_Flow[i].ucR_Num==ucR_Num)
  7.         {
  8.             return &stA_Flow[i];
  9.         }
  10.     }
  11.     return (flow_t*)0; //没有找到
  12. }

  13. flow_t * S_Log_Flow_Ctrl(flow_t * stP_Flow)
  14. {
  15.     switch(stP_Flow->eR_Mode)
  16.     {
  17.                 case Value_Flow_Start:
  18.                 case Value_Flow_Delay:
  19.         {
  20.             delay_ms(stP_Flow->ul_DelayMs);
  21.             return S_Log_Flow_Found(stP_Flow->ucR_NumNext);
  22.         }
  23.         //break;
  24.         case Value_Flow_Work:
  25.         {
  26.             MX_GPIO_Set(stP_Flow->ucR_OutPutNum,stP_Flow->ucR_OutPutData);
  27.             return S_Log_Flow_Found(stP_Flow->ucR_NumNext);
  28.         }
  29.         //break;
  30.         case Value_Flow_Judge:
  31.         {
  32.             if(MX_GPIO_Get(stP_Flow->ucR_InPutNum))
  33.             {
  34.                 return S_Log_Flow_Found(stP_Flow->ucR_NumNext);
  35.             }
  36.             else
  37.             {
  38.                 return S_Log_Flow_Found(stP_Flow->ucR_NumFalseNext);
  39.             }
  40.             
  41.         }
  42.         //break;
  43.         default:
  44.         {
  45.             return stP_Flow;
  46.         }
  47.         //break;
  48.     }
  49.     //return stP_Flow;
  50. }

复制代码

怎么过动作流程,自动的执行了?其实很简单。如下所示,一直在运行下去

  1. while(1)
  2.         {
  3.                 stP_Flow=S_Log_Flow_Ctrl(stP_Flow);
  4.         //OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_PERIODIC,&err);//延时5ms
  5.         }

复制代码


回到例子,任务函数如下所示

  1. void flow_ctrl_task(void *p_arg)
  2. {
  3.         flow_t * stP_Flow = &stA_Flow[0];
  4.         
  5.    
  6.         //开始
  7.         S_Log_Flow_Free(&stA_Flow[0]);
  8.         stA_Flow[0].ucR_Num  = 0;
  9.     stA_Flow[0].eR_Mode  = Value_Flow_Start;
  10.     stA_Flow[0].ucR_NumNext      = 1;
  11.     stA_Flow[0].ul_DelayMs       = 500;
  12.     stA_Flow[0].ucR_OutPutNum    = 0;
  13.     stA_Flow[0].ucR_OutPutData   = 0;
  14.     stA_Flow[0].ucR_NumFalseNext = ucR_Num_Null;
  15.     stA_Flow[0].ucR_InPutNum     = 0;
  16.         
  17.         //按钮停==true
  18.         S_Log_Flow_Free(&stA_Flow[1]);
  19.         stA_Flow[1].ucR_Num  = 1;
  20.     stA_Flow[1].eR_Mode  = Value_Flow_Judge;
  21.     stA_Flow[1].ucR_NumNext      = 5;//电机停止
  22.     stA_Flow[1].ul_DelayMs       = 500;
  23.     stA_Flow[1].ucR_OutPutNum    = 0;
  24.     stA_Flow[1].ucR_OutPutData   = 0;
  25.     stA_Flow[1].ucR_NumFalseNext = 2;//限位开关==true
  26.     stA_Flow[1].ucR_InPutNum     = 0;//端口0输入
  27.         
  28.         //限位开关==true
  29.         S_Log_Flow_Free(&stA_Flow[2]);
  30.         stA_Flow[2].ucR_Num  = 2;
  31.     stA_Flow[2].eR_Mode  = Value_Flow_Judge;
  32.     stA_Flow[2].ucR_NumNext      = 5;//电机停止
  33.     stA_Flow[2].ul_DelayMs       = 0;
  34.     stA_Flow[2].ucR_OutPutNum    = 0;
  35.     stA_Flow[2].ucR_OutPutData   = 0;
  36.     stA_Flow[2].ucR_NumFalseNext = 3;//按钮关门==true
  37.     stA_Flow[2].ucR_InPutNum     = 1;//端口1输入
  38.         
  39.         //按钮关门==true
  40.         S_Log_Flow_Free(&stA_Flow[3]);
  41.         stA_Flow[3].ucR_Num  = 3;
  42.     stA_Flow[3].eR_Mode  = Value_Flow_Judge;
  43.     stA_Flow[3].ucR_NumNext      = 4;//电机正转
  44.     stA_Flow[3].ul_DelayMs       = 0;
  45.     stA_Flow[3].ucR_OutPutNum    = 0;
  46.     stA_Flow[3].ucR_OutPutData   = 0;
  47.     stA_Flow[3].ucR_NumFalseNext = 5;//电机停止
  48.     stA_Flow[3].ucR_InPutNum     = 2;//端口2输入
  49.         
  50.         //电机正转
  51.         S_Log_Flow_Free(&stA_Flow[4]);
  52.         stA_Flow[4].ucR_Num  = 4;
  53.     stA_Flow[4].eR_Mode  = Value_Flow_Work;
  54.     stA_Flow[4].ucR_NumNext      = 0;//开始
  55.     stA_Flow[4].ul_DelayMs       = 0;
  56.     stA_Flow[4].ucR_OutPutNum    = 0;
  57.     stA_Flow[4].ucR_OutPutData   = 1;//正转
  58.     stA_Flow[4].ucR_NumFalseNext = ucR_Num_Null;
  59.     stA_Flow[4].ucR_InPutNum     = 0;
  60.         
  61.         //电机停止
  62.         S_Log_Flow_Free(&stA_Flow[5]);
  63.         stA_Flow[5].ucR_Num  = 5;
  64.     stA_Flow[5].eR_Mode  = Value_Flow_Work;
  65.     stA_Flow[5].ucR_NumNext      = 0;//开始
  66.     stA_Flow[5].ul_DelayMs       = 0;
  67.     stA_Flow[5].ucR_OutPutNum    = 0;
  68.     stA_Flow[5].ucR_OutPutData   = 0;//停止
  69.     stA_Flow[5].ucR_NumFalseNext = ucR_Num_Null;
  70.     stA_Flow[5].ucR_InPutNum     = 0;
  71.         
  72.         while(1)
  73.         {
  74.                 stP_Flow=S_Log_Flow_Ctrl(stP_Flow);
  75.         //OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_PERIODIC,&err);//延时5ms
  76.         }
  77. }

复制代码


二、显示
只能说是丑陋的界面,满屏的文字,其实还有很多优化的地方。日后再来慢慢改善。



三、缺点与日后改善
时间过得真的很快,不经不觉就两个月。对于一个全新的项目与思维,真心觉得两个月的时间是不够的。现在只能做到这个样子,下一步,
1、应该是流程图支持拖放,
2、依据类型自动变换形状,
3、流程节点采用动作生成
4、利用连线进行按序
5、多流程的并行操作
6、流程图的掉电保存

要做的东西很多,只能一步步来了!后面还要继续完美代码。代码就迟些上传
四、感悟
ALIENTEK 阿波罗 STM32F767 开发板确实是做得很好的板子,更给力的是有丰富的例程,提供给新手们参考学习。
特别是
STM32F7开发指南-HAL库版本_V1.0.pdf
STM32F767 EMWIN开发手册_V1.0.pdf
节省了很多的时间,为项目争取更多时间

小编有演示视频嘛?

强强

小编有演示视频嘛

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top