1、 机械与车辆学院机电控制系统仿真与软件设计报告(2013-2014学年第一学期)课程设计题目:机电控制系统设计与仿真 姓名:学号:班级:指导老师:时间:成绩:目录一、课程设计性质和目的- 2 -二、课程设计的内容及要求- 2 -三、课程设计的进度及安排- 3 -四、MATLAB/Stateflow学习- 4 -五、水位控制系统模型- 4 -六、嵌入式C代码- 5 -七、调试运行及分析- 7 -八、心得体会- 7 -九、参考文献- 8 -十、致谢- 8 -十一、附录- 9 -附录1 simulink水位控制模型- 9 -附录2 stateflow 水位控制模型- 10 -附录3 proteus水
2、塔控制仿真- 11 -附录4 ert_main.c函数文件- 12 -附录5 rt_zcfcn.c函数文件- 15 -附录6 untitled.c函数文件- 18 -附录7 untitled_data.c函数文件- 24 -一、课程设计性质和目的机械电子工程专业是一个对实践、应用能力要求很强的专业,机电控制系统设计与仿真课程学习的目的是让学生借助MATLAB软件来研究机电控制系统的设计方法,与传统控制系统设计采用直接编写程序代码不同的是,本课程是在MATLAB/SIMULINK中设计出控制系统模型,再通过Embedded Coder将控制系统模型生成可执行的C代码,然后加载至MCU中去,采用这
3、种新颖的方法,不用再专注于繁琐程序代码的编写工作,而可以将精力花费在控制算法的研究上。通过学习本课程让学生也了解现代控制行业发展趋势及控制系统实现的先进方法。 二、课程设计的内容及要求在Proteus中建立起水位控制系统仿真模型,如图1所示。B表示为下限水位传感器,C表示为上限水位传感器,D1为指示灯,电机为泵。图1 水位控制系统仿真模型 下限水位传感器B接单片机P1.0管脚,上限水位传感器接单片机P1.1管脚,指示灯D1接单片机P1.3管脚,电机由单片机P1.2经过光耦和继电器来控制。 工作过程是水位未到下限水位时,泵工作抽水,同时D1指示灯常亮,水位上升到下限水位继续上升,当水位上升到上限
4、水位时,泵停止工作,同时D1指示灯灭,如果下限水位传感器未动作,而上限水位传感器却动作了,则泵停止工作,同时指示灯D1开始按一定时间间隔闪烁报警。根据上述的控制要求在SIMULINK中,运用Stateflow工具箱建立起该控制系统的模型,并进行仿真运行分析,达到控制系统要求后,再通过SIMULINK菜单code选项,c/c+ code/build model,生成嵌入式C代码。然后在Keil中对生成的C代码进行I/O配置和适当修改,编译成HEX文件,最后将该HEX文件加载至Proteus仿真平台就可以验证代码的正确性了。三、课程设计的进度及安排表一:时间分配进度表序号项 目时 间1布置设计任务
5、、初步运用MATLAB基本知识6号上午2进一步熟悉MATLAB,SIMULINK各种设置的熟悉6号下午3流水灯控制系统SIMULINK建模练习7号上午4流水灯控制系统SIMULINK建模仿真,控制代码的自动生成和编译c代码修改、编译与仿真7号下午5水位控制系统SIMULINK建模8号上午6控制代码的自动生成和编译c代码修改、编译调试与仿真8号下午7仿真控制系统调试分析、编写设计报告9号上午8课程设计报告的整理9号下午9打印课程设计报告10号上午10答辩10号下午四、MATLAB/Stateflow学习MATLAB是一种科学计算软件,专门以矩阵的形式处理数据。MATLAB将高性能的数值计算能力和
6、强大的数字可视化功能集成在一起,提供了大量的内置函数,因而被广泛地应用于科学计算、控制系统、信息处理等领域的分析仿真和设计工作;而Stateflow是集成于Simulink中的图形化设计与开发工具,主要用于针对控制系统中的复杂控制逻辑进行建模和仿真,即适用于对事件响应系统进行建模和仿真。Stateflow和Simulink结合起来,可以创建确定性监管控制系统。利用Stateflow可视化的模型和直观的仿真能力,可以清晰、简洁地反映出动态逻辑关系。它的基础是有限状态机理论,它通过状态图、流程图的创建,对事件驱动系统进行建模和仿真。此次课程设计是基于MATLAB/Stateflow软件上的一次实践
7、,利用Stateflow可视化的模型和直观的仿真能力,对水塔进行逻辑图的绘制,建立动态系统模型进行仿真。然后对仿真出来的代码进行修改和添加。这样就不需要花太多时间从事代码的开发 ,可以让设计者腾出更多的精力进行顶层控制策略的设计。采用Stateflow 进行系统建模 ,直观、逻辑关系清晰、简便 ,RTW 生成执行代码正确 ,可以大大缩短系统开发周期。五、水位控制系统模型首先新建一个 simulink文件 ,然后在 simulink library 中的 stateflow 模型库中拉出一个char,建立如附录1 所示的水位控制模型。分为三个状态 ,状态 1 为 motor_off(抽水电机停止
8、状态),此时 led=0(指示灯灭),motor=0(抽水电机停止),状态 2为 motor_on(电机运行状态),此时 led=1(指示灯亮),motor=1(电机运行),状态 3 为 error(故障状态),此时 motor=0(电机停止),led 闪烁(由子状态来实现),led_on 和 led_off 状态间的转移条件为 delay 事件(在后面生成的代码中进行添加 ,用定时中断来做)。状态 1、状态 2、状态 3 之间的转移条件为水位传感器 B、C 来决定。下限传感器 B 动作时 sensor_B=0,上限传感器C 动作时 ,sensor_C=0。通过菜单栏打开 model expl
9、orer,设置触发事件和 I/O,led、motor 为输出 ,数据类型选择为 uint8,sensor_B,sensor_C 为输入 ,数据类型选择为 uint8。delay 为转移条件用 fail(下降边沿触发)。并为 simulink 控制模型添加输入和输出 ,如附录2 所示。设定好stateflow了以后,再设置simulink中的Configuration Parameters,Solver options中Type选择定步长Fixed-step,其他默认;硬件Hardware Implement选项Device vendor选择Intel,Device type选择8051,其他默
10、认;Real-time Workshop中,System target file选项选择ert.tlc,编译语言language选择C,其他默认。 六、嵌入式C代码在simulink菜单中Tools选择Real-time Workshop下的Build Model,在matlab命令窗口command window中可以看到详细的编译步骤,编译成功后,simulink文件所在文件夹会出现名为untitled_ert_rtw的文件夹。在该文件夹下,建立如附录3所示的proteus仿真模型,取名为水塔电路图;并建立名为untitled的keil新工程,芯片选择ATMEL公司的AT89C51,接下来
11、要将rtw编译所得到的C源文件导入keil中修改并进行编译生成单片机可执行的.hex文件。在keil工程中,Source Group 1导入rtw编译所得到的C源文件,共有3个,一个为ert_main.c、一个为untitled.c还有rt_zcfcn.c,ert_main.c为主程序,里面要设定输入输出端口,untitled.c为功能程序。然后修改ert_main.c文件,头文件处加入#include,并对所到的管脚进行定义,sbit P1_0=P10;sbit P1_1=P11;sbit P1_2=P12;sbit P1_3=P13;其中输入输出管脚的名称,可以在untitled.c中查找
12、得到,必须保持一致。 在/*set the model*/ 前加untitled_U.sensor_B=P1_0;untitled_U.sensor_C=P1_1;在/*get model outputs here*/P1_3=untitled_Y.Out1;P1_2=untitled_Y.Out2;将int_T main(int_T argc,const char_T *argv)改成int_T main()将如下程序段屏蔽或者删除。Print(“warning:The simulation will run forever.”“Generated ERT main wontt simula
13、te model step behavior.”“To chang this behavior select the MAT-file logging option./n”)在while循环体中添加rt_OneStep();在 Initialize model 中设置定时器 ,去掉 printf指令和 fflush(NULL),(void)(argc);。最后Perform other application tasks here 处添加 rt_OneStep()函数调用 ,设置好后 ,进行编译并生成 HEX 文件。在代码的修改中出现了一个很粗心的错误,就是将输出口的接口搞反了, P1_2=u
14、ntitled_Y.Out1;P1_3=untitled_Y.Out2;正确的应该是P1_2=untitled_Y.Out2;P1_3=untitled_Y.Out1;结果,足足多花了两个小时。matlab编译完的C代码:#include #include untitled.h #include rtwtypes.h void rt_OneStep(void) static boolean_T OverrunFlag = 0; if (OverrunFlag) rtmSetErrorStatus(untitled_M, Overrun); return; OverrunFlag = TRUE;
15、 untitled_step(); OverrunFlag = FALSE;int_T main(int_T argc, const char *argv) (void)(argc); (void)(argv); untitled_initialize(); printf(Warning: The simulation will run forever. Generated ERT main wont simulate model step behavior. To change this behavior select the MAT-file logging option.n); fflu
16、sh(NULL); while (rtmGetErrorStatus(untitled_M) = (NULL) untitled_terminate(); return 0;七、调试运行及分析修改完,经过编译正确,将编译好的hex文件导入proteus软件中进行仿真,见图4。当水位低于下限 ,B、C 未触发时 ,抽水电机运行抽水 ,指示灯点亮。当水位高于下限低于上限,B触发,C 未触发时 ,抽水电机运行抽水 ,指示灯点亮。当水位上升至上限 ,B、C 均触发时 ,抽水电机停止抽水 ,指示灯灭。出现错误时,电机停止运转,指示灯闪烁。八、心得体会通过本次水位控制系统的Matlab机电控制系统设计与仿
17、真, 使我Matlab的应用有了一个深刻的认识,也有了一个全面的提高。这主要得益于老师耐心的教诲与同学们提供资料与帮助的结果。通过这次课程设计,我学到了一个全新的软件,让自己在理论知识和软件操作能力方面都得到了很好的训练!还学会了充分利用网络资源等一切可以利用的资源。九、参考文献 1 王静霞 主编,单片机应用技术,电子工业出版社,2009. 2 Mathworks Corp. Stateflow Users Guide R2013aZ, 2013. 3 刘杰 主编,基于模型的设计MCU篇,北京航空航天大学出版社,2011. 4张威. Matlab. Stateflow逻辑系统建模,西安电子科技
18、大学出版社,2007.十、致谢在此,我对我的指导老师王倩老师致以我最衷心的感谢与诚挚的敬意!王老师干劲十足,易于亲近,而且在对学生是非常负责,一次次耐心地指导我。如果没有她的悉心教诲,我顺利完成我的课程设计!同时,也非常感谢在这期间帮助过我的所有同学,谢谢你们的帮助!感谢我们的王倩老师。十一、附录附录1 simulink水位控制模型附录2 stateflow 水位控制模型附录3 proteus水塔控制仿真word文档 可自由复制编辑附录4 ert_main.c函数文件/* * File: ert_main.c * * Code generated for Simulink model unti
19、tled. * * Model version : 1.2 * Simulink Coder version : 8.4 (R2013a) 13-Feb-2013 * TLC version : 8.4 (Jan 19 2013) * C/C+ source code generated on : Thu Jan 09 10:22:05 2014 * * Target selection: ert.tlc * Embedded hardware selection: Intel-8051 Compatible * Code generation objectives: Unspecified
20、* Validation result: Not run */#include /* This ert_main.c example uses printf/fflush */#include untitled.h /* Models header file */#include rtwtypes.h /* MathWorks types */#includesbit 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
21、 service routine * is what makes the generated code real-time. The 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 specif
22、ic. This * example code indicates where these should take place relative 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(
23、void) static boolean_T OverrunFlag = 0; /* Disable interrupts here */ /* Check 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
24、.sensor_C=P1_1; untitled_U.sensor_B=P1_0; /* Step the model */ untitled_step(); /* Get model outputs 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
25、here */* * The example main function illustrates what is required by your * application code to initialize, execute, 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
26、 main() /* Unused arguments */ /(void)(argc); /(void)(argv); /* Initialize model */ untitled_initialize(); /* Attach rt_OneStep to a timer or interrupt service routine with * period 0.5 seconds (the models base sample time) here. The * call syntax for rt_OneStep is * * rt_OneStep(); */ /* printf(War
27、ning: The simulation will run forever. Generated ERT main wont simulate model step behavior. To change this behavior select the MAT-file logging option.n); fflush(NULL); */ while (rtmGetErrorStatus(untitled_M) = (NULL) /* Perform other application tasks here */ rt_OneStep(); /* Disable rt_OneStep()
28、here */ /* Terminate model */ untitled_terminate(); return 0;/* * File trailer for generated code. * * EOF */附录5 rt_zcfcn.c函数文件/* * File: rt_zcfcn.c * * Code generated for Simulink model untitled. * * Model version : 1.2 * Simulink Coder version : 8.4 (R2013a) 13-Feb-2013 * TLC version : 8.4 (Jan 19
29、 2013) * C/C+ source code generated on : Thu Jan 09 10:22:05 2014 * * Target selection: ert.tlc * Embedded hardware selection: Intel-8051 Compatible * Code generation objectives: Unspecified * Validation result: Not run */#include rt_zcfcn.h/* Detect zero crossings events. */ZCEventType rt_ZCFcn(ZCD
30、irection 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_NUL, SL_ZCS_EVENT_Z2P, SL_ZCS_EVENT_Z2N, SL_ZCS_EVENT_NU
31、L ,/* 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_NUL /* UNK */ ; /* get prevZcEvent and prevZcSign from p
32、revZc */ slZcEventType prevEv = (slZcEventType)(uint8_T)(*prevZc) 2); slZcSignalSignType prevSign = (slZcSignalSignType)(uint8_T)(*prevZc) & 0x03); /* get current zcSignal sign from current zcSignal value */ slZcSignalSignType currSign = (slZcSignalSignType)(currValue) 0.0 ? SL_ZCS_SIGN_POS : (currV
33、alue) 0.0 ? SL_ZCS_SIGN_NEG : SL_ZCS_SIGN_ZERO); /* get current zcEvent based on prev and current zcSignal value */ slZcEventType currEv = eventMatrixprevSigncurrSign; /* get slZcEventType from ZCDirection */ switch (zcDir) case ANY_ZERO_CROSSING: zcsDir = SL_ZCS_EVENT_ALL; break; case FALLING_ZERO_
34、CROSSING: zcsDir = SL_ZCS_EVENT_ALL_DN; break; case RISING_ZERO_CROSSING: zcsDir = SL_ZCS_EVENT_ALL_UP; break; default: zcsDir = SL_ZCS_EVENT_NUL; break; /*had event, check if double zc happend remove double detection. */ if (slZcHadEvent(currEv, zcsDir) currEv = (slZcEventType)(slZcUnAliasEvents(pr
35、evEv, currEv); else currEv = SL_ZCS_EVENT_NUL; /* Update prevZc */ tempEv = (slZcEventType)(currEv 8051 Compatible * Code generation objectives: Unspecified * Validation result: Not run */#include untitled.h#include untitled_private.h/* Named constants for Chart: /Chart */#define untitled_IN_NO_ACTI
36、VE_CHILD (uint8_T)0U)#define untitled_IN_error (uint8_T)1U)#define untitled_IN_led_off (uint8_T)1U)#define untitled_IN_led_on (uint8_T)2U)#define untitled_IN_motor_on (uint8_T)2U)#define untitled_IN_motor_ooff (uint8_T)3U)/* Block states (auto storage) */DW_untitled_T untitled_DW;/* Previous zero-cr
37、ossings (trigger) states */PrevZCX_untitled_T untitled_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
38、_;RT_MODEL_untitled_T *const untitled_M = &untitled_M_;/* Model step function */void untitled_step(void) real_T rtb_delay; ZCEventType zcEvent; /* DiscretePulseGenerator: /delay */ rtb_delay = (untitled_DW.clockTickCounter = 0L) ? untitled_P.delay_Amp : 0.0; if (untitled_DW.clockTickCounter = untitl
39、ed_P.delay_Period - 1.0) untitled_DW.clockTickCounter = 0L; else untitled_DW.clockTickCounter+; /* End of DiscretePulseGenerator: /delay */ /* Chart: /Chart incorporates: * TriggerPort: /delay */ zcEvent = rt_ZCFcn(FALLING_ZERO_CROSSING,&untitled_PrevZCX.Chart_Trig_ZCE, (rtb_delay); if (zcEvent != N
40、O_ZCEVENT) /* Gateway: Chart */ /* Event: :1 */ /* During: Chart */ if (untitled_DW.is_active_c1_untitled = 0U) /* Entry: Chart */ untitled_DW.is_active_c1_untitled = 1U; /* Inport: /sensor_C incorporates: * Inport: /sensor_B */ /* Entry Internal: Chart */ if (untitled_U.sensor_C = 0) & (untitled_U.sensor_B = 0) /* Transition: :11 */ untitled_DW.is_c1_unti