当前位置:文档之家› 电梯运行模拟控制器

电梯运行模拟控制器

目录1.课程设计简介 (1)1.1简介 (1)1.2设计总电路图 (2)1.3实物图 (4)2.设计题目 (4)3.总体设计 (6)3.1电梯运行模拟控制器的总体运作流程 (6)3.2电梯运行模拟控制器各模块关系 (6)4.详细设计 (7)6.1基本的IO配置(输入/输出模式) (7)输出模式配置 (7)输入模式配置 (7)6.2外部中断配置 (8)定时器中断 (8)外部按键输入中断 (8)6.3电梯运行逻辑设计(软件编码) (9)数据结构设计 (9)功能接口设计 (9)5.体会与总结 (10)6.附录 (11)源代码 (11)参考文献 (26)1.课程设计简介1.1简介本设计使用STM8S系列作为主控芯片,使用矩阵键盘、若干个LED和两位数码管作为外设。

其中矩阵键盘用来模拟电梯按键,若干个LED灯用来模拟电梯的运动方向、楼层的指示灯(电梯内部楼层对应的按钮),两位的数码管用于显示电梯目前所处楼层。

1.2设计总电路图(基于AD这个平台生成的PCB图与原理图)原理图原理图PCB图PCB图1.3实物图实物图2.设计题目设计一个电梯运行模拟控制器,其系统框图如下图所示:电梯运行模拟控制器框图功能要求:能够模拟控制一个8层楼梯的电梯的运行。

具体要求如下: 1.电梯平时没有接到命令时候或者执行完命令后停在1楼,门关闭.。

2.电梯运行速度2秒一层楼3.电梯门在开启的情况下没有收到命令10秒中后自动关闭。

在运动中门必须关闭,(最后3秒可以设置音响警告信号)4.一句话,电梯控制器满足实际电梯的运行要求,电梯在运行的时候可以最多记住8个命令。

并且综合考虑公平性(先按键先执行)和有效性(完成任务的总的行走路径最短)来执行。

要求完成的内容:1.完成硬件电路的设计与安装调试(可借助单片机实验电路板),并用CAD 软件画出原理电路图。

2.画出流程图,编写并调试驱动程序。

3.撰写设计报告。

MCU1位七段数码管,3个LED 灯(显示当前电梯所处楼层与运行方向以及键盘以及对应的LED 灯(1-8,开门,关门)每个数字按键对应一个LED 灯,按下按键灯亮,8个LE D灯显示电梯所2个灯显示当前电梯8×2-2=14个按键表示每层楼入口的电梯按键3.1 电梯运行模拟控制器的总体运作流程等待外部信号整体配置初始化收到中断信号?执行电梯处理逻辑是否电梯运行模拟控制器整体运作流程3.2 电梯运行模拟控制器各模块关系电梯运行模拟控制器各模块关系图6.1基本的IO配置(输入/输出模式)输出模式配置对于输出模式IO的配置,用到的外设(LED灯,数码管,矩阵键盘),在代码中都有对它们进行对应的配置。

其中将LED的对应的IO口配置成推挽输出模式。

当然数码管也是相同的配置方式,所以不做赘述。

输出模式的引脚的配置输入模式配置对于IO口为输入模式的配置,将矩阵键盘设为输入模式,等待外部去触发。

输入模式的引脚的配置6.2外部中断配置定时器中断此设计使用了定时器中断用于每2s产生一个中断信号,这个信号的作用是让主控芯片知道当前(正在运动的)电梯的所处楼层发生了变化(向上运动了一层或是向下运动了一层)。

定时器中断配置外部按键输入中断此设计使用外部按键输入中断,用来及时检测电梯内部、外部的楼层按钮被按下的情况,每当有按钮被按下就产生信号使主控芯片进行相应的逻辑处理。

外部按键输入中断(部分)6.3电梯运行逻辑设计(软件编码)数据结构设计在电梯运行期间,电梯的运行方向、电梯当前所处楼层、电梯内部的哪几个对应的按钮被按下需要被存储下来。

以及当外部有按钮被按下时,需要记录当前被按下的按钮编号所以设计了以下的数据结构。

数据结构设计功能接口设计为了让模拟电梯的控制器的运作与现实的电梯相似,需要设计相应的接口以便模拟控制器以正确的逻辑正常运作。

功能接口设计5.体会与总结对于这次的课设,我个人认为这是大学以来工程量最大的课设,因为它涉及了软件方便的编码,还有硬件方面的PCB制版还有最后就是要自行编写一个规范的文档报告,总的来说工作的内容还是比较丰富的。

在软件编码方面,由于C语言有一段时间没有去使用了,所以在对单片机进行裸机编程的时候,我去复习了单片机原理和C语言的相关书籍,以便我去选择更好的数据结构用来存储数据。

在软件编码过程中,比较有意思的就是去设计电梯运作逻辑,在设计这个逻辑时,我自己也再次对我们生活中的电梯运作流程进行了进一步的观察。

这个逻辑相对于比较有挑战性的就是,你要让你写的逻辑穿插在硬件层和软件曾中正常运行,所以在DEBUG的时候也比较难去查问题,由于自己也比较懒,在DEBUG的时候懒得用那个仿真调试的功能,导致最后解决BUG的时间花的还是比较多的。

在硬件PCB板制作方面,主要就是去学习怎样去使用AD这个专业的画板软件,自己也第一次去用化学药剂腐蚀的方法去制作最小版,自己动手去做一个小玩意儿的经历也是很有意思的。

在文档编写方面,由于之前上了WORD的选修,所以我也就趁这次机会,把之前所学的只是进行学以致用,这次文档的编写我尽量按照毕业课设的规范来要求自己,以求让文档的格式看起来更加的让人赏心悦目。

6.附录源代码#include "iostm8s105c6.h"#include <stdio.h>#include <stdbool.h>/**宏定义***/#define Floors 8/***全局数组,变量**/int floorState[Floors + 1] = {0,0,0,0,0,0,0,0,0}; /**true表示有该楼层的请求还未处理,false表示在该楼层没有请求**/unsigned char DisDisplay[10] ={0X00,0XF3,0X49,0X61,0X33,0X25,0X05,0XF1,0X01,0X7F};int FloorNow = 1; //电梯所处的楼层unsigned char i = 0; //解决定时器第一次中断问题unsigned char j = 0; //解决电梯按下关门请求后会自动开门的变量unsigned char Temp1 = 0; //计数为两秒用(电梯上升楼层的间隔时间)unsigned char Temp2 = 0; //10s,自动关门用unsigned char FloorPoint = 0; //记忆指针unsigned char FloorStart = 0; //记忆初始位置unsigned char FloorOver = 0; //记忆终止位置unsigned char Index = 0;int bottonNum = -1;int direction = -2; /**初始值为-2**/int floorToGo = -1; /**楼梯将要去的楼层***/void DisBegin(void); //初始化内部数码管和上下说明void LedBegin(void); //初始化内部LED函数声明void KeyBegin(void); //初始化键盘输入函数声明void BreakPoint(void); //键盘中断优先级函数初始化void Running(void); //电梯运行函数声明void TIM1_Init(void); //定时器初始化函数声明void DoorJudge(void); //中断内开关门的判断程序void delay(unsigned int time); //延时函数声明void Floor_To_Go(); //吐出要去的楼层命令void Judge_Direction();void Step_one(int bottonNum);void main(void) {LedBegin(); //LED初始化KeyBegin(); //键盘初始化DisBegin(); //内部数码管初始化__asm("sim");BreakPoint(); //键盘中断初始化TIM1_Init(); //定时器初始化TIM1_CR1 = 0X04; //置CEN零,先不计数//TIM1_CR1 = 0X01; //开始计数__asm("rim"); //开总中断while (1) {Running(); //电梯运行s/**在主循环内要频繁的去对比,电梯运行到的当前楼层是否到达了最近需要去到达的楼层(最迫切去处理的请求)**/if (FloorNow == floorToGo) {floorState[FloorNow] = 0; /**清除当前楼层的请求**/}//上下指示灯的行为步骤if (direction == 0) {PG_ODR = 0XFD;}else if(direction == 1) {PG_ODR = 0XFE;}else {PG_ODR |= 0XFF; //到达楼层,关掉上下指示灯}}}//初始化内部LED函数定义void LedBegin(void) {PD_DDR = 0XFF;PD_CR1 = 0XFF;PD_CR2 = 0X00;PD_ODR = 0XFF;PE_DDR = 0XFF;PE_CR1 = 0XFF;PE_CR2 = 0X00;PE_ODR = 0X00; //初始化开关门指示灯的同时顺便初始化按键使其输出全零扫描码PG_DDR = 0XFF; //初始化方向指示灯PG_CR1 = 0XFF;PG_CR2 = 0X00;PG_ODR = 0XFF;}//初始化内部数码管void DisBegin(void) {PC_DDR = 0XFF;PC_CR1 = 0XFF;PC_CR2 = 0X00;}//初始化键盘输入函数定义void KeyBegin(void) {//初始化键盘输出与输入PA_DDR = 0XFF; //初始化开关门键输出全零扫描码PA_CR1 = 0XFF;PA_CR2 = 0X00;PA_ODR = 0X00;PB_DDR = 0X00; //两个矩阵键盘的输入检测PB_CR1 = 0XFF;PB_CR2 = 0XFF;}//键盘中断初始化函数定义void BreakPoint(void){ITC_SPR2 = 0X03;EXTI_CR1 = 0X08;}//定时器初始化函数定义void TIM1_Init(void) {TIM1_SMCR = 0X00;TIM1_ETR = 0X00;TIM1_SR1 &= 0XEF; //先清除一次更新中断标志TIM1_PSCRH = 0;TIM1_PSCRL = (unsigned char)199; //对2MHz进行200分频,之后频率为10kHzTIM1_IER = 0X01; //开启溢出中断TIM1_ARRH = (unsigned char)(10000 >> 8);TIM1_ARRL = (unsigned char)10000; //数10000次,记为1sTIM1_CNTRH =0 ;//(unsigned char)(20000 >> 8);TIM1_CNTRL =0 ;//(unsigned char)20000; //先溢出一次}//电梯运行函数定义void Running(void) {PC_ODR = DisDisplay[FloorNow];unsigned char FloorLed = 0;for(Index = Floors;Index >= 1; Index --) {FloorLed = FloorLed + floorState[Index];if (Index == 1) break;FloorLed <<= 1;PD_ODR = ~FloorLed;}#pragma vector = 13__interrupt void TIM1_OVF_IRQ(void) {i ++;if(i > 1) {Temp1 ++;if(Temp1 > 1) { //判定为两秒if(floorToGo > 0 && floorToGo < 9) {if(FloorNow < floorToGo) { //去往请求楼层FloorNow ++;PG_ODR = 0XFE; //上指示灯Temp2 = 0;j = 0; //关门bug解决变量回位}else if(FloorNow > floorToGo) {FloorNow --;PG_ODR = 0XFE; //下指示灯Temp2 = 0;j = 0; //关门bug解决变量回位}else if (FloorNow == floorToGo){ //到达楼层DoorJudge();}Temp1 = 0;}else {DoorJudge();}} else;TIM1_SR1 = 0X00; //清除更新中断标志}#pragma vector = 6 //用于判断按下了哪里的按钮__interrupt void KeyScan(void) {TIM1_SR1 = 0X00; //先清除一次更新中断标志TIM1_CR1 = 0X05; //开始计数i = 0;PE_ODR |= 0XFE;PE_ODR &= 0XFD; //内部第一行检测if((PB_IDR & 0X0F) != 0X0F) {delay(50);if((PB_IDR & 0X0F) != 0X0F) {switch (PB_IDR & 0X0F) {case 0X0E:bottonNum = 1;break;case 0X0D:bottonNum = 2;break;case 0X0B:bottonNum = 3;break;case 0X07:bottonNum = 4;break;default:break;}}}PE_ODR |= 0XFE;PE_ODR &= 0XFB; //内部第二行检测if((PB_IDR & 0X0F) != 0X0F) {delay(50);if((PB_IDR & 0X0F) != 0X0F) {switch (PB_IDR & 0X0F) {case 0X0E:bottonNum = 5;break;case 0X0D:;bottonNum = 6;break;case 0X0B:bottonNum = 7;break;case 0X07:bottonNum = 8;break;default:break;}}}PE_ODR |= 0XFE;PE_ODR &= 0XF7; //内部第三行开关请求检测if((PB_IDR & 0X0F) != 0X0F) {delay(50);if((PB_IDR & 0X0F) != 0X0F) {switch (PB_IDR & 0X0F) {case 0X0E: //开门请求{if((FloorNow == floorToGo) || (floorToGo == -1)) {PE_ODR |= 0X01;} else ;}break;case 0X0D: //关门请求PE_ODR &= 0XFE;j ++;break;default:break;}}}PE_ODR |= 0XFE; //用完一次行扫描就关闭本次行扫描码进行其他判断,判断完了重新开就是了PA_ODR = 0XF7; //外部按键第一行检测if((PB_IDR & 0XF0) != 0XF0) {delay(50);if((PB_IDR & 0XF0) != 0XF0) {switch (PB_IDR & 0XF0) {case 0XE0:bottonNum = 1;break;case 0XD0:bottonNum = 2;break;case 0XB0:bottonNum = 3;break;case 0X70:bottonNum = 4;break;default:break;}}}PA_ODR = 0XEF; //外部按键第二行检测if((PB_IDR & 0XF0) != 0XF0) {delay(50);if((PB_IDR & 0XF0) != 0XF0) {switch (PB_IDR & 0XF0) {case 0XD0:bottonNum = 2;break;case 0XB0:bottonNum = 3;break;case 0X70:bottonNum = 4;break;default:break;}}}PA_ODR = 0XDF; //外部按键第三行检测if((PB_IDR & 0XF0) != 0XF0) {delay(50);if((PB_IDR & 0XF0) != 0XF0) {switch (PB_IDR & 0XF0) {case 0XE0:bottonNum = 5;break;case 0XD0:bottonNum = 6;break;case 0XB0:bottonNum = 7;break;default:break;}}}PA_ODR = 0XBF; //外部按键第四行检测if((PB_IDR & 0XF0) != 0XF0) {delay(50);if((PB_IDR & 0XF0) != 0XF0) {switch (PB_IDR & 0XF0) {case 0XE0:bottonNum = 5;break;case 0XD0:bottonNum = 6;break;case 0XB0:bottonNum = 7;break;case 0X70:bottonNum = 8;break;default:break;}}}Step_one(bottonNum);Judge_Direction();Floor_To_Go();//if(HXFloorNow != floorToGo) { //目的楼层亮灯判断if(floorToGo != -1) {PE_ODR &= 0XFE; //电梯移动时的强制关门指令} else;//上下指示灯的行为步骤if (direction == 0){PG_ODR = 0XFD;}else if(direction == 1){PG_ODR = 0XFE;}else{PG_ODR |= 0XFF; //到达楼层,关掉上下指示灯}PE_ODR &= 0X01; //继续输出全零扫描码PA_ODR = 0X00;}//中断内开关电梯门判断程序void DoorJudge(void) {Temp2 ++; //开始计数(10s)PG_ODR = 0XFF; //再次确认关掉上下指示灯if(Temp2 > 5) { //到了10sPE_ODR &= 0XFE; //把门关上Floor_To_Go();}else { //没到10sif(j > 0) { //但是有人按了关门键PE_ODR &= 0XFE; //那就关门Floor_To_Go();}else { //如果没人按键盘PE_ODR |= 0X01; //那就先开着电梯门}}}void delay(unsigned int time) {while(time --);}/**当按钮按下时,将会触发外部中断**//***外部中断的第一步将会修改全局数组*/void Step_one(int bottonNum){if (bottonNum != FloorNow)floorState[bottonNum] = 1;}/***外部中断的第二步将会判断direction变量的取值*/ void Judge_Direction(){int i; bool flag = 0;if (direction == -2) /**此时电梯处于刚开机的状态**/ {direction = 1; /**电梯运行方向为向上**/ }else if (direction == 1) /**当电梯在向上运行时**/ {for (i = FloorNow + 1; i <= Floors; i++)if (floorState[i] == 1){ flag = 1; return; }if (flag == 0)for (i = FloorNow - 1; i >= 1; i--)if (floorState[i] == 1){ flag = 1; direction = 0; return;} if (flag == 0) {direction = -1; return;}}else if (direction == 0) /**当电梯在向下运行时**/{for (i = FloorNow - 1; i >= 1; i--)if (floorState[i] == 1){ flag = 1; return;}if (flag == 0)for (i = FloorNow + 1; i <= Floors; i++)if (floorState[i] == 1){ flag = 1; return;}if (flag == 0) {direction = -1; return;}}else if (direction == -1) /**电梯再次静止**/{int a = 0, b = 0, i, flag1 = 0, flag2 = 0;for (i = FloorNow + 1; i <= Floors; i++)if (floorState[i] == 1){a = i; flag1 = 1;}for (i = FloorNow - 1; i >= 1; i--)if (floorState[i] == 1){b = i; flag2 = 1;}if (flag1 == 1 && flag2 == 1)if (a - FloorNow >= FloorNow - b)direction = 0;elsedirection = 1;if (flag1 == 1 && flag2 == 0)direction = 1;else if (flag1 == 0 && flag2 == 1)direction = 0;else if (flag1 == 0 && flag2 == 0)direction = -1;}return;}/***外部中断的第三步将会反馈此刻电梯应该跑向的楼层的取值*/void Floor_To_Go(){int i = 0;if (direction == -1) { floorToGo = -1; return;}else if (direction == 1) /**当电梯运行方向是向上时,如果发现有一个次对于当前楼层的请求,则返回这个请求数值**/for (i = FloorNow + 1; i <= Floors; i++) { if(floorState[i] == 1) {floorToGo = i; return;}}else if (direction == 0) /**同理于上**/for (i = FloorNow - 1; i >= 1; i--) { if(floorState[i] == 1) {floorToGo = i; return;}}direction = -1;floorToGo = -1;}参考文献[1] 郑诗卫. 印制电路板排版设计. 北京:科学技术文献出版社,1983[2] 潘永雄, 沙何等. 电子线路CAD实用教程.第三版. 西安:西安电子科技大学出版社,2007[3] 潘永雄. 新编单片机原理与应用实验. 西安:西安电子科技大学出版社,2005。

相关主题