1、 机械与车辆学院机电控制系统仿真与软件设计报告(2014-2015 学年第一学期)课程设计题目:水塔水位机电控制系统设计与仿真- 1 -一、课程设计性质和目的机械电子工程专业是一个对实践、应用能力要求很强的专业,机电控制系统设计与仿真课程学习的目的是让学生借助 MATLAB 软件来研究机电控制系统的设计方法,与传统控制系统设计采用直接编写程序代码不同的是,本课程是在MATLAB/SIMULINK 中设计出控制系统模型,再通过 Embedded Coder 将控制系统模型生成可执行的 C 代码,然后加载至 MCU 中去,采用这种新颖的方法,不用再专注于繁琐程序代码的编写工作,而可以将精力花费在控
2、制算法的研究上。通过学习本课程让学生也了解现代控制行业发展趋势及控制系统实现的先进方法。二、课程设计的内容及要求在 Proteus 中建立起水位控制系统仿真模型,如图所示:B 表示为下限水位传感器,C 表示为上限水位传感器,D1 为指示灯,电机为泵。图 1 水位控制系统仿真模型下限水位传感器 B 接单片机 P1.0 管脚,上限水位传感器接单片机 P1.1 管脚,指示灯 D1 接单片机 P1.3 管脚,电机由单片机 P1.2 经过光耦和继电器来控制。- 2 -工作过程是:(1)水位未到下限水位时,泵工作抽水,同时 D1 指示灯常亮,水位超过下限水位继续上升。(2)当水位上升到上限水位时,泵停止工
3、作,同时 D1 指示灯灭,(3)如果下限水位传感器未动作,而上限水位传感器却动作了,则泵停止工作,同时指示灯 D1 开始按一定时间间隔闪烁报警。(4)根据上述的控制要求在 SIMULINK 中,运用 Stateflow 工具箱建立起该控制系统的模型,并进行仿真运行分析,达到控制系统要求后,再通过 SIMULINK菜单 code 选项,c/c+ code/build model,生成嵌入式 C 代码。然后在 Keil中对生成的 C 代码进行 I/O 配置和适当修改,编译成 HEX 文件,最后将该 HEX文件加载至 Proteus 仿真平台就可以验证代码的正确性了。三、课程设计的进度及安排序号 项
4、 目 时 间1 布置任务,讲授 MATLAB 基本知识 1 天2 水塔水位控制系统 SIMULINK 建模仿真 1 天3 控制代码的自动生成和修改、编译与仿真 1 天4 仿真控制系统调试分析、编写设计报告 1 天5 答辩 1 天表 1 课程安排四、MATLAB/Stateflow 学习通过 MATLAB 是一种科学计算软件,专门以矩阵的形式处理数据。MATLAB 将高性能的数值计算能力和强大的数字可视化功能集成在一起,提供了大量的内置函数,因而被广泛地应用于科学计算、控制系统、信息处理等领域的分析仿真和设计工作;而 Stateflow 是集成于 Simulink 中的图形化设计与开发工具,主要
5、用于针对控制系统中的复杂控制逻辑进行建模和仿真,即适用于对事件响应系统进行建模和仿真。Stateflow 和- 3 -Simulink 结合起来,可以创建确定性监管控制系统。利用 Stateflow 可视化的模型和直观的仿真能力,可以清晰、简洁地反映出动态逻辑关系。它的基础是有限状态机理论,它通过状态图、流程图的创建,对事件驱动系统进行建模和仿真。 此次课程设计是基于 MATLAB/Stateflow 软件上的一次实践,利用 Stateflow 可视化的模型和直观的仿真能力,对水塔进行逻辑图的绘制,建立动态系统模型进行仿真。然后对仿真出来的代码进行修改和添加。这样就不需要花太多时间从事代码的开
6、发 ,可以让设计者腾出更多的精力进行顶层控制策略的设计。采用 Stateflow 进行系统建模 ,直观、逻辑关系清晰、简便 ,RTW 生成执行代码正确 ,可以大大缩短系统开发周期。五、水位控制系统模型首先在 matlab2013asimulink 下建立起水塔水位控制模型如图 2 所示,并保存。图 2 simulink 下建立控制模型In1、In2 为控制输入端(P1.0 口、P1.1 口的按键输入) ,设定信号名称为delay,该信号作为 stateflow 中状态之间变换的转换条件(等效按键的按下产生的脉冲) 。Out1、Out2 为模型的输出端。 (电机和指示灯的输出端口)在 state
7、flow 菜单 view 下的 Model Explorer 中设定输入、输出。输入- 4 -High_a,port 为 1,数据类型 DataType 为 uit8,输入 low_b,port 为 1,数据类型DataType 为 uit8,输入 delay 触发 Trigger 为 Falling(因为单片机中,设置是按键按下时产生一个下降沿)。输出为 M、led,port 分别为 1、2,数据类型DataType 为 uit8 如图所示。图 3 Model Explorer 输入输出设定Chart 模块为 stateflow 模块,定义了 High_a、Low_b 两个输入变量、M、le
8、d 两个输出端口。- 5 -图 4 stateflow 建模初始状态:有 4 种不同的情况 High_a 和 Low_b 都为 1;High_a 和 Low_b 都为0;High_a 为 1,Low_b 为 0;High_a 为 0,Low_b 为 1。这 4 种状态将直接进入四种不同的固定状态,执行相应的命令。四种固定状态:(1)状态 A 为(工作状态):水位在水位的下限 Low_b 下,输入信号 High_a 和Low_b 都为 1。M(抽水电机工作状态) ,此时 led=1(指示灯亮) 。(2)状态 A1 为(故障状态):水位在水位的下限 High_a 以上,未到达水位上限Low_b。
9、,此时 motor=0(电机停止) ,led 闪烁(由子状态来实现)A4、A5 状态间的转移以 delay 条件实现亮灭。图 5 A1 模型- 6 -(3)状态 A2 为(中间状态):电机和指示灯都保持原来的运行状态不变。(4)状态 A3 为(停机状态):水位在水位的下限 Low_b 以上,也到达水位上限High_a。M(抽水电机停止状态) ,此时 led=0(指示灯灭) 。(5)delay 事件(delay 为转移条件用 fail(下降边沿触发) 。(6)状态 1、状态 2、状态 3 之间的转移条件为水位传感器 B、C 来决定。 (即由输入信号 High_a 和 Low_b 决定)当输入信号
10、 High_a 和 Low_b 都为 1,进入状态 A 执行命令。完毕后进入中间状态 A2,等待下一个输入信号(High_a 和 Low_b)的变化,再选择进入相应的状态执行命令。图 6 状态及状态转换设定好 stateflow 了以后,再设置 simulink 中的 Configuration Parameters,Solver options 中 Type 选择定步长 Fixed-step,其他默认;硬件Hardware Implement 选项 Device vendor 选择 Intel, Device type 选择 8051,其他默认;Real-time Workshop 中,Sy
11、stem target file 选项选择 ert.tlc,编译语言language 选择 C,其他默认。- 7 -然后在 simulink 菜单中 Tools 选择 Real-time Workshop 下的 Build Model,在 matlab 命令窗口 command window 中可以看到详细的编译步骤,编译成功后,simulink 文件所在文件夹会出现名为 test_ert_rtw 的文件夹,在该文件夹下,建立 如图所示的 proteus 仿真模型,取名为 test;并建立名为 test 的 keil 新工程,芯片选择 ATMEL 公司的 AT89C51,接下来要将 rtw 编
12、译所得到的 C 源文件导入 keil 中修改并进行编译生成单片机可执行的.hex 文件。六、嵌入式 C 代码描在 simulink 菜单中 Tools 选择 Real-time Workshop 下的 Build Model,在matlab 命令窗口 command window 中可以看到详细的编译步骤,编译成功后,simulink 文件所在文件夹会出现名为 untitled_ert_rtw 的文件夹。在该文件夹下,建立如附录 3 所示的 proteus 仿真模型,取名为水塔电路图;- 8 -并建立名为 untitled 的 keil 新工程,芯片选择 ATMEL 公司的 AT89C51,接
13、下来要将 rtw 编译所得到的 C 源文件导入 keil 中修改并进行编译生成单片机可执行的.hex 文件。 在 keil 工程中,Source Group 1 导入 rtw 编译所得到的 C 源文件,共有 3 个,一个为 ert_main.c、一个为 untitled.c 还有 rt_zcfcn.c,ert_main.c 为主程序,里面要设定输入输出端口,untitled.c 为功能程序。 图 7 导入 C 源文件(1)如果不进行修改,直接编译会报错,不能编译通过。主要是要修改ert_main.c 文件,打开后在头文件处加入#include,并对所到的管脚进行定义。如图所示。图 8 修改头文
14、件和加入管脚定义(2)接下来设定模型输入输出管脚,如图所示。- 9 -图 9 添加模型输入输出管脚(3)其中输入输出管脚的名称,可以在 test.c 中查找得到,必须保持一致。接下来,要对 main 函数进行修改。改成(4)将如下程序段屏蔽或者删除。在 while 循环体中添加 rt_OneStep();即变成将程序中的(void)(argc);fflush(NULL);程序段屏蔽如图所示。(5)进行编译,会提示找不到 solver_zc.h 文件,解决办法为:在 matlab 安装目录下,搜索查找 solver_zc.h,将找到的这个文件,复制到 test_ert_rtw 的文件夹即可,然后
15、右键点击 keil 工程中 Target 1,选择 Options for Target Target 1中 Output,选择 Creat HEX file,设定好了后,点击编译,成功- 10 -编译后,便得到 test.hex 文件,再打开 proteus 仿真模型,双击 AT89C51芯片,加载 test.hex 文件,运行便得到了任务要求的效果。七、调试运行及分析修改完,经过编译正确,将编译好的 hex 文件导入 proteus 软件中进行仿真,见图 4。当水位低于下限 ,B、C 未触发时 ,抽水电机运行抽水 ,指示灯点亮。当水位高于下限低于上限,B 触发,C 未触发时 ,抽水电机运行
16、抽水 ,指示灯点亮。当水位上升至上限 ,B、C 均触发时 ,抽水电机停止抽水 ,指示灯灭。出现错误时,电机停止运转,指示灯闪烁。图 10 proteus 仿真模型八、心得体会(1)在第一次设计与仿真练习过程中遇到了许多的问题其中:在改写嵌入 C语言编译时因为没有屏蔽原程序中的 void)(argc);fflush(NULL);语句导致程序无法编译。- 11 -(2)在第一次的仿真控制 8 个 LED 灯时,8 个 LED 灯全都点亮。开始时以为是程序模型的错误,经过多次的检查证实了程序模型没有错误。最后在同学的帮助下,发现了是在嵌入 C 语言编译中,rt_OneStep(); 没有放入主函数中
17、。(3)在水塔水位机电系统设计与仿真实验中:仿真时发现了 proteus 仿真模型的运行状态不正确,通过多次的检查发现了在 stateflow 建模时有一个输入端口没有大写,导致输入端口的信号不能与模型连接。(4)通过本次水位控制系统的 Matlab 机电控制系统设计与仿真, 使我 Matlab的应用有了一个深刻的认识,也有了一个全面的提高。这主要得益老师耐心的教诲与同学们提供资料与帮助的结果。 通过这次课程设计,我学到了一个全新的软件,让自己在理论知识和软件操作能力方面都得到了很好的训练!还学会了充分利用网络资源等一切可以利用的资源九、参考文献1 王静霞.单片机应用技术,电子工业出版社.20
18、09. 2 Mathworks Corp. Stateflow Users Guide R2013aZ.2013. 3 刘杰.基于模型的设计MCU 篇,北京航空航天大学出版社.2011.4 张威. Matlab. Stateflow 逻辑系统建模,西安电子科技大学出版社.2007.十、致谢在本次课程设计中许多同学给予我帮助,解决了不少在课程设计中遇到的问题。同时也帮助我自己获取了许多过去没有的学到的知识。在这里我要特别感谢唐伟杰老师的耐心教导,郑建伟同学的建议和提醒!附录/* File: ert_main.c* Code generated for Simulink model untitle
19、d.* Model version : 1.6* Simulink Coder version : 8.5 (R2013b) 08-Aug-2013* C/C+ source code generated on : Sun Oct 26 23:45:21 2014* Target selection: ert.tlc* Embedded hardware selection: Intel-8051 Compatible* Code generation objectives: Unspecified* Validation result: Not run*/#include /* This e
20、rt_main.c example uses printf/fflush */#include “untitled.h“ /* Models header file */#include “rtwtypes.h“#include sbit P1_0=P10;sbit P1_1=P11;sbit P1_2=P12;sbit P1_3=P13;/* Associating rt_OneStep with a real-time clock or interrupt service routine* is what makes the generated code “real-time“. The
21、function rt_OneStep is* always associated with the base rate of the model. Subrates are managed* by the base rate from inside the generated code. Enabling/disabling* interrupts and floating point context switches are target specific. This* example code indicates where these should take place relativ
22、e to executing* the generated code step function. Overrun behavior should be tailored to* your application needs. This example simply sets an error status in the* real-time model and returns from rt_OneStep.*/void rt_OneStep(void)static boolean_T OverrunFlag = 0;/* Disable interrupts here */* Check
23、for overrun */if (OverrunFlag) rtmSetErrorStatus(untitled_M, “Overrun“);return;OverrunFlag = TRUE;/* Save FPU context here (if necessary) */* Re-enable timer or interrupt here */* Set model inputs here */untitled_U.In2=P1_0;untitled_U.In1=P1_1;/* Step the model */untitled_step();/* Get model outputs
24、 here */P1_2=untitled_Y.Out2;P1_3=untitled_Y.Out1;/* Indicate task complete */OverrunFlag = FALSE;/* Disable interrupts here */* Restore FPU context here (if necessary) */* Enable interrupts here */* The example “main“ function illustrates what is required by your* application code to initialize, ex
25、ecute, and terminate the generated code.* Attaching rt_OneStep to a real-time clock is target specific. This example* illustates how you do this relative to initializing the model.*/int_T main()/* Unused arguments */(void)(argc);/(void)(argv);/* Initialize model */untitled_initialize();/* Attach rt_
26、OneStep to a timer or interrupt service routine with* period 0.5 seconds (the models base sample time) here. /* Disable rt_OneStep() here */* Terminate model */untitled_terminate();return 0;/* File trailer for generated code.* EOF*/- 12 -/* File: rt_zcfcn.c* Code generated for Simulink model untitle
27、d.* Model version : 1.6* Simulink Coder version : 8.5 (R2013b) 08-Aug-2013* C/C+ source code generated on : Sun Oct 26 23:45:21 2014* Target selection: ert.tlc* Embedded hardware selection: Intel-8051 Compatible* Code generation objectives: Unspecified* Validation result: Not run */#include “rt_zcfc
28、n.h“/* Detect zero crossings events. */ZCEventType rt_ZCFcn(ZCDirection zcDir, ZCSigState* prevZc, real_T currValue)slZcEventType zcsDir;slZcEventType tempEv;ZCEventType zcEvent = NO_ZCEVENT; /* assume */* zcEvent matrix */static const slZcEventType eventMatrix44 = /* ZER POS NEG UNK */ SL_ZCS_EVENT
29、_NUL, SL_ZCS_EVENT_Z2P, SL_ZCS_EVENT_Z2N, SL_ZCS_EVENT_NUL ,/* ZER */ SL_ZCS_EVENT_P2Z, SL_ZCS_EVENT_NUL, SL_ZCS_EVENT_P2N, SL_ZCS_EVENT_NUL ,/* POS */ SL_ZCS_EVENT_N2Z, SL_ZCS_EVENT_N2P, SL_ZCS_EVENT_NUL, SL_ZCS_EVENT_NUL ,/* NEG */ SL_ZCS_EVENT_NUL, SL_ZCS_EVENT_NUL, SL_ZCS_EVENT_NUL, SL_ZCS_EVENT
30、_NUL /* UNK*/;The* call syntax for rt_OneStep is* rt_OneStep();*/fflush(NULL);while (rtmGetErrorStatus(untitled_M) = (NULL) /* Perform other application tasks here */rt_OneStep();/* Disable rt_OneStep() here */* Terminate model */untitled_terminate();return 0;/* File trailer for generated code.* EOF
31、*/- 13 -/* get prevZcEvent and prevZcSign from prevZc */slZcEventType prevEv = (slZcEventType)(uint8_T)(*prevZc) 2);slZcSignalSignType prevSign = (slZcSignalSignType)(uint8_T)(*prevZc) /* get current zcSignal sign from current zcSignal value */slZcSignalSignType currSign = (slZcSignalSignType)(currV
32、alue) 0.0 ?SL_ZCS_SIGN_POS :(currValue) 8051 Compatible* Code generation objectives: Unspecified* Validation result: Not run*/#include “untitled.h“#include “untitled_private.h“/* Named constants for Chart: /Chart1 */#define untitled_IN_A (uint8_T)1U)#define untitled_IN_A1 (uint8_T)2U)#define untitle
33、d_IN_A2 (uint8_T)3U)#define untitled_IN_A3 (uint8_T)4U)#define untitled_IN_A4 (uint8_T)1U)#define untitled_IN_A5 (uint8_T)2U)#define untitled_IN_NO_ACTIVE_CHILD (uint8_T)0U)/* Block states (auto storage) */DW_untitled_T untitled_DW;/* Previous zero-crossings (trigger) states */PrevZCX_untitled_T unt
34、itled_PrevZCX;/* External inputs (root inport signals with auto storage) */ExtU_untitled_T untitled_U;/* External outputs (root outports fed by signals with auto storage) */ExtY_untitled_T untitled_Y;/* Real-time model */RT_MODEL_untitled_T untitled_M_;RT_MODEL_untitled_T *const untitled_M = /* Mode
35、l step function */void untitled_step(void)real_T rtb_PulseGenerator;ZCEventType zcEvent;/* DiscretePulseGenerator: /Pulse Generator */rtb_PulseGenerator = (untitled_DW.clockTickCounter = 0L) ? untitled_P.PulseGenerator_Amp : 0.0;if (untitled_DW.clockTickCounter = untitled_P.PulseGenerator_Period - 1
36、.0) untitled_DW.clockTickCounter = 0L; else untitled_DW.clockTickCounter+;/* End of DiscretePulseGenerator: /Pulse Generator */* Chart: /Chart1 incorporates:* TriggerPort: /delay */zcEvent = rt_ZCFcn(FALLING_ZERO_CROSSING,if (zcEvent != NO_ZCEVENT) /* Gateway: Chart1 */* Event: :29 */* During: Chart
37、1 */if (untitled_DW.is_active_c2_untitled = 0U) /* Entry: Chart1 */untitled_DW.is_active_c2_untitled = 1U;/* Inport: /In2 incorporates:* Inport: /In1*/* Entry Internal: Chart1 */if (untitled_U.In2 = 1) /* Outport: /Out1 */* Entry A: :2 */untitled_Y.Out1 = 1U;/* Outport: /Out2 */- 15 -else switch (un
38、titled_DW.is_c2_untitled) case untitled_IN_A:/* Inport: /In2 incorporates:* Inport: /In1*/* During A: :2 */if (untitled_U.In2 = 1) /* Outport: /Out2 */* Entry A2: :4 */untitled_Y.Out2 = 0U;break;case untitled_IN_A1:/* Inport: /In2 incorporates:* Inport: /In1*/* During A1: :3 */if (untitled_U.In2 = 0
39、) untitled_DW.is_c2_untitled = untitled_IN_A3;/* Outport: /Out1 */* Entry A3: :5 */untitled_Y.Out1 = 0U;/* Outport: /Out2 */untitled_Y.Out2 = 0U;else if (untitled_DW.is_A1 = untitled_IN_A4) /* During A4: :13 */* Transition: :16 */untitled_DW.is_A1 = untitled_IN_A5;untitled_Y.Out2 = 1U; else if (unti
40、tled_U.In2 = 1) /* Outport: /Out2 */* Entry A2: :4 */untitled_Y.Out2 = 0U; else if (untitled_U.In2 = 0) /* Outport: /Out1 */* Entry A3: :5 */untitled_Y.Out1 = 0U;/* Outport: /Out2 */untitled_Y.Out2 = 0U; else if (untitled_U.In2 = 0) /* Outport: /Out1 */* Entry A1: :3 */untitled_Y.Out1 = 0U;/* Entry
41、Internal A1: :3 */* Transition: :18 */untitled_DW.is_A1 = untitled_IN_A4;/* Outport: /Out2 */* Entry A4: :13 */untitled_Y.Out2 = 0U;- 16 -/* Outport: /Out2 */* Entry A5: :14 */untitled_Y.Out2 = 1U; else /* During A5: :14 */* Transition: :17 */untitled_DW.is_A1 = untitled_IN_A4;/* Outport: /Out2 */*
42、Entry A4: :13 */untitled_Y.Out2 = 0U;break;case untitled_IN_A2:/* Inport: /In2 incorporates:* Inport: /In1*/* During A2: :4 */if (untitled_U.In2 = 0) /* Outport: /Out1 */* Entry A1: :3 */untitled_Y.Out1 = 0U;/* Entry Internal A1: :3 */* Transition: :18 */untitled_DW.is_A1 = untitled_IN_A4;/* Outport
43、: /Out2 */* Entry A4: :13 */untitled_Y.Out2 = 0U;break;default:/* Inport: /In2 incorporates:* Inport: /In1 */* During A3: :5 */if (untitled_U.In2 = 1) /* Outport: /Out1 */* Entry A: :2 */untitled_Y.Out1 = 1U;/* Outport: /Out2 */untitled_Y.Out2 = 1U;break;/* Model initialize function */void untitled_
44、initialize(void)/* Registration code */* initialize error status */rtmSetErrorStatus(untitled_M, (NULL);/* states (dwork) */(void) memset(void *)/* external inputs */(void) memset(void *)/* external outputs */(void) memset(void *)/* Start for DiscretePulseGenerator: /Pulse Generator */untitled_DW.cl
45、ockTickCounter = 0L;untitled_PrevZCX.Chart1_Trig_ZCE = UNINITIALIZED_ZCSIG;/* InitializeConditions for Chart: /Chart1 */untitled_DW.is_A1 = untitled_IN_NO_ACTIVE_CHILD;untitled_DW.is_active_c2_untitled = 0U;untitled_DW.is_c2_untitled = untitled_IN_NO_ACTIVE_CHILD;/* InitializeConditions for Outport:
46、 /Out1 incorporates:* InitializeConditions for Chart: /Chart1*/- 17 -/* File: untitled_data.c* Code generated for Simulink model untitled.* Model version : 1.8* Simulink Coder version : 8.5 (R2013b) 08-Aug-2013* C/C+ source code generated on : Mon Oct 27 18:01:33 2014* Target selection: ert.tlc* Emb
47、edded hardware selection: Intel-8051 Compatible* Code generation objectives: Unspecified* Validation result: Not run*/#include “untitled.h“#include “untitled_private.h“/* Block parameters (auto storage) */P_untitled_T untitled_P = 1.0, /* Expression: 1Referenced by: /delay*/20.0, /* Computed Paramet
48、er: delay_Period* Referenced by: /delay*/1.0, /* Computed Parameter: delay_Duty* Referenced by: /delay*/0.0 /* Expression: 0* Referenced by: /delay*/;/* File trailer for generated code.* EOF*/untitled_Y.Out2 = 0U;/* Model terminate function */void untitled_terminate(void)/* (no terminate code required) */* File trailer for generated code.* EOF*/